├── Debugging.md ├── LICENSE ├── README.md ├── blockchain-network-on-kubernetes ├── artifacts │ ├── chaincode │ │ └── ngo_collaboration │ │ │ └── ngo_collaboration.go │ ├── configtx.yaml │ └── crypto-config.yaml ├── configFiles │ ├── blockchain-services.yaml │ ├── chaincode_install.yaml │ ├── chaincode_instantiate.yaml │ ├── copyArtifactsJob.yaml │ ├── createVolume-paid.yaml │ ├── createVolume.yaml │ ├── create_channel.yaml │ ├── docker-volume.yaml │ ├── docker.yaml │ ├── generateArtifactsJob.yaml │ ├── join_channel.yaml │ └── peersDeployment.yaml ├── deleteNetwork.sh ├── setup_blockchainNetwork_v1.sh └── setup_blockchainNetwork_v2.sh ├── fabric-java-sdk-app ├── WebContent │ └── META-INF │ │ └── MANIFEST.MF ├── manifest.yml ├── pom.xml └── src │ └── main │ └── java │ └── org │ └── example │ ├── client │ ├── CAClient.java │ ├── ChannelClient.java │ └── FabricClient.java │ ├── config │ └── ConfigNetwork.java │ ├── servlet │ ├── CreateNeedServlet.java │ ├── CreatePledgeServlet.java │ ├── QueryAllActiveNeedsServlet.java │ ├── QueryAllNeedsServlet.java │ ├── QueryAllPastNeedsServlet.java │ ├── QueryAllPledgesForNeedServlet.java │ ├── QueryNeedServlet.java │ └── QueryPledgeServlet.java │ ├── user │ ├── CAEnrollment.java │ ├── RegisterEnrollUser.java │ └── UserContext.java │ └── util │ └── Util.java ├── images ├── architecture.png ├── webui-active-needs.png ├── webui-create-need.png ├── webui-login.png ├── webui-past-needs.png ├── webui-pledge-qty.png ├── webui-pledge-updated-qty.png ├── webui-pledges-for-a-need.png ├── webui-tasks.png └── worker-nodes.png └── webapp ├── .gitignore ├── app.js ├── bin └── www ├── config.js ├── manifest.yml ├── package.json ├── public └── stylesheets │ └── style.css ├── routes ├── createneed.js ├── dashboard.js ├── index.js ├── login.js ├── menu.js ├── needdetails.js ├── pastneeds.js └── users.js └── views ├── createneed.ejs ├── dashboard.ejs ├── error.ejs ├── index.ejs ├── login.ejs ├── menu.ejs ├── needdetails.ejs └── pastneeds.ejs /Debugging.md: -------------------------------------------------------------------------------- 1 | * If chaincode instantion fails during setup of Blockchain network on Kubernetes, check the logs of Chaincode-instantiation pod. If error says: 2 | 3 | ``` 4 | Error: could not assemble transaction, err proposal response was not successful, error code 500, msg error starting container: error starting container: cannot connect to Docker endpoint 5 | ``` 6 | 7 | It means you are using IKS 1.11.x or more but have not modified `blockchain-network-on-kubernetes/configFiles/peersDeployment.yaml` as mentioned in Step 2. Please perform the step as explained, network will be setup successfully. 8 | 9 | * While running `kubectl` commands, if you get error as: 10 | 11 | ``` 12 | The connection to the server localhost:8080 was refused - did you specify the right host or port? 13 | ``` 14 | It means environment is not set properly. Export KUBECONFIG path, it will work. To get more details on KUBECONFIG value, refer to the `Access` tab of your cluster in IBM Cloud Dashboard. 15 | 16 | * If there is connection related exception in the Liberty runtime logs, please check whether the IP address of the Kubernetes network has been specified correctly in the `manifest.yml` file as described in Step 3 (Build the client application based on Fabric Java SDK). 17 | 18 | ``` 19 | org.hyperledger.fabric_ca.sdk.exception.EnrollmentException: Url:http://xxx.xx.xx.xxx:30054, Failed to enroll user admin 20 | at org.hyperledger.fabric_ca.sdk.HFCAClient.enroll(HFCAClient.java:518) 21 | ... 22 | Caused by: org.apache.http.conn.HttpHostConnectException: Connect to xxx.xx.xx.xxx:30054 [/xxx.xx.xx.xxx] failed: Operation timed out (Connection timed out) 23 | ... 24 | Caused by: java.net.ConnectException: Operation timed out (Connection timed out) 25 | at java.net.PlainSocketImpl.socketConnect(Native Method) 26 | ``` 27 | 28 | * During running the web application, if you get the following error: 29 | 30 | ``` 31 | This page isn’t working 32 | ``` 33 | 34 | It means that the url of the Java SDK application might not be right. Ensure that the Java SDK application url is provided correctly in config.js file of webapp. 35 | 36 | ``` 37 | This site can’t be reached 38 | ``` 39 | It means that Java SDK application might not be running. Ensure that the Java SDK application is up and running. 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ## NOTE: This repository has been archived and no longer maintained! 3 | 4 | # Facilitate collaboration between non-governmental organizations using blockchain 5 | 6 | ### Use Hyperledger Fabric to manage supply and demand of goods to be distributed to the needy 7 | 8 | NGO is a non-profit organization that operates independently of any government and is a social voluntary organization of social activist, group of persons, community, volunteers and citizens who are associated for social welfare and social development. NGOs are usually funded by donations, but some avoid formal funding altogether and are run primarily by volunteers. Every NGO has its own mission and objectives. 9 | 10 | When there is a person/organization in need, they approach NGO for help. But all the times, the requirement cannot be fulfilled by any one NGO or sometimes end user does not know which NGO to reach out for a specific requirement. In such hard times, NGOs should avoid competition and compromise and instead co-operate to achieve better results. But misunderstandings and collaboration without trust can prevent partnerships from reaching their potential. 11 | 12 | Hence here is a blockchain based solution for NGO collaboration, in which NGOs with a diverse/same portfolios can come forward and be a part of consortium. When one approaches an NGO with some need (say books for education), that NGO can not help for this need or it can not be fulfilled by that NGO alone, then that NGO will create a new request in the network. All other NGOs whoever can contribute will update the request over the blockchain network. This network will give the holistic view of the requirement and its current status. This way a need is catered to in an efficient manner. The problems of over collection or under collection for a need is reduced. The platform brings in trust, accountability and transparency of operations between NGOs. 13 | 14 | This composite pattern demonstrates a solution using a combination of other individual code patterns. 15 | - [Deploy Hyperledger Fabric network on IBM Cloud](https://github.com/IBM/blockchain-network-on-kubernetes) 16 | - [Create and deploy a blockchain network using Hyperledger Fabric SDK for Java](https://github.com/IBM/blockchain-application-using-fabric-java-sdk) 17 | 18 | When the reader has completed this Code Pattern, they will understand how to: 19 | 20 | - Setup blockchain Network on Kubernetes directly through configuration files not using [Blockchain Platform 2.0]((https://cloud.ibm.com/catalog/services/blockchain-platform-20)) as a service on IBM Cloud 21 | - Interact with blockchain network using Fabric Java SDK 22 | - Build a client application which will interact with blockchain network with the help of SDK 23 | 24 | # Flow 25 | 26 | ![](images/architecture.png) 27 | 28 | 1. Setup Blockchain Network using Kubernetes configuration files on IBM Cloud. 29 | 2. Deploy the client application using Fabric Java SDK. It works as middle layer and exposes REST API. 30 | 3. Deploy Web UI application built using NodeJs. 31 | 4. User can perform following task using the web interface which internally interacts with Blockchain Network with the help of middle layer. 32 | * Create a new need 33 | * Pledge for a need 34 | * View needs 35 | 36 | 37 | # Pre-requisites 38 | 39 | * [IBM Cloud Account](https://cloud.ibm.com) 40 | * [Git Client](https://git-scm.com/downloads) - needed for clone commands. 41 | * [Maven](https://maven.apache.org/install.html) 42 | * [Nodejs](https://nodejs.org/en/download/) 43 | 44 | # Steps 45 | 46 | Follow these steps to setup and run this code pattern. The steps are described in detail below. 47 | 48 | 1. [Get the code](#1-get-the-code) 49 | 2. [Deploy Hyperledger Fabric Network using Kubernetes on IBM Cloud](#2-deploy-hyperledger-fabric-network-using-kubernetes-on-ibm-cloud) 50 | 3. [Build the client application based on Fabric Java SDK](#3-build-the-client-application-based-on-fabric-java-sdk) 51 | 4. [Build and deploy webapp](#4-build-and-deploy-webapp) 52 | 5. [Analyze the Results](#5-analyze-the-results) 53 | 54 | ## 1. Get the code 55 | 56 | - Clone the repo using the below command. 57 | ``` 58 | git clone https://github.com/IBM/ngo-collaboration-using-blockchain 59 | ``` 60 | 61 | - In this repository, 62 | * [Network setup](https://github.com/IBM/ngo-collaboration-using-blockchain/tree/master/blockchain-network-on-kubernetes): configuration files and scripts to deploy Hyperledger Fabric network using Kubernetes on IBM Cloud. 63 | * [Client code using Fabric Java SDK](https://github.com/IBM/ngo-collaboration-using-blockchain/tree/master/fabric-java-sdk-app): application code built using Fabric Java SDK to invoke and query chaincode on the hyperledger fabric network. The operations are exposed as ReST APIs when deployed enabling other applications to consume. 64 | * [Web application code](https://github.com/IBM/ngo-collaboration-using-blockchain/tree/master/webapp): NodeJS based application code to render UI and integrates with the ReST APIs exposed by the client application built on Fabric Java SDK. 65 | 66 | 67 | ## 2. Deploy Hyperledger Fabric Network using Kubernetes on IBM Cloud 68 | 69 | In this step, we will setup the Hyperledger Fabric network using Kubernetes. For detailed steps, please refer to the [Deploy blockchain network on Cloud](https://github.com/IBM/blockchain-network-on-kubernetes). 70 | 71 | The scripts and configuration files to setup the network for this pattern can be located at `blockchain-network-on-kubernetes`. Perform the following steps to setup the network. 72 | 73 | * Create a [Kubernetes Service](https://cloud.ibm.com/kubernetes/catalog/cluster?bss_account=01fedb4f3ff70b186d83cdb1e1e0cbc8) instance using IBM Cloud dashboard. 74 | * Gain access of your Kubernetes cluster as explained in `step 3` in [repository](https://github.com/IBM/blockchain-network-on-kubernetes) and ensure you are able to run `kubectl` commands properly. 75 | * In case of IKS 1.11.x or greater, modify the `blockchain-network-on-kubernetes/configFiles/peersDeployment.yaml` file to point to a Docker service. Change instances of `unix:///host/var/run/docker.sock` to `tcp://docker:2375` with a text editor or use the commands below. 76 | ``` 77 | ## macOS 78 | $ sed -i '' s#unix:///host/var/run/docker.sock#tcp://docker:2375# configFiles/peersDeployment.yaml 79 | 80 | ## Linux 81 | $ sed -i s#unix:///host/var/run/docker.sock#tcp://docker:2375# configFiles/peersDeployment.yaml 82 | ``` 83 | 84 | * Choose the appropriate script to setup the network as per your environment. For this, check your kubectl CLI version as: 85 | 86 | ``` 87 | $ kubectl version --short 88 | ``` 89 | 90 | This command will give you `Client Version` and `Server Version`. 91 | If the `Client version > v1.11.x` i.e. 1.12.x or more then use `setup_blockchainNetwork_v2.sh` to set up the network. Run 92 | the following command: 93 | 94 | ``` 95 | cd blockchain-network-on-kubernetes 96 | cp setup_blockchainNetwork_v2.sh setup_blockchainNetwork.sh 97 | ``` 98 | 99 | If the `Client version <= v1.11.x` then use `setup_blockchainNetwork_v1.sh` to setup the network. Copy the script as shown. 100 | ``` 101 | cd blockchain-network-on-kubernetes 102 | cp setup_blockchainNetwork_v1.sh setup_blockchainNetwork.sh 103 | ``` 104 | 105 | 106 | * Execute the following steps to setup the network. 107 | ``` 108 | cd blockchain-network-on-kubernetes 109 | chmod +x setup_blockchainNetwork.sh 110 | ./setup_blockchainNetwork.sh 111 | ``` 112 | * If there is a need to delete the network, execute the following steps. 113 | ``` 114 | $ chmod +x deleteNetwork.sh 115 | $ ./deleteNetwork.sh 116 | ``` 117 | 118 | **Get the public IP of your Kubernetes Cluster** 119 | 120 | After setting up your network, find out the public IP of your cluster. It will be required for further steps. 121 | 122 | * Go to IBM Cloud Dashboard. 123 | 124 | * Click on your Kubernetes Cluster under `Clusters` section on Dashboard. It gives you details of the cluster. 125 | 126 | * Access `Worker Nodes` tab, it will show you the public IP of your cluster as shown in below screenshot. 127 | 128 | ![](images/worker-nodes.png) 129 | 130 | Make a note of this public IP. It will be used in next step. 131 | 132 | 133 | ## 3. Build the client application based on Fabric Java SDK 134 | 135 | Here, we use the [Fabric Java SDK](https://github.com/hyperledger/fabric-sdk-java) to build a client to invoke and query chaincode on the hyperledger fabric network. 136 | 137 | The first step is to specify the public IP address of the Kubernetes Cluster. The public IP address can be found on the `Kubernetes Dashboard` as described in the previous section. 138 | 139 | Open the `manifest.yml` file under `fabric-java-sdk-app` directory. Enter the public IP address of the Kubernetes Cluster for the variable `KUBERNETES_IP_ADDRESS`, and save the file. 140 | 141 | ``` 142 | applications: 143 | - name: ngo-collaboration-java-app 144 | random-route: true 145 | memory: 256M 146 | path: target/ngo-collaboration-java.war 147 | buildpack: liberty-for-java 148 | env: 149 | KUBERNETES_IP_ADDRESS: xxx.xxx.xx.xx 150 | ``` 151 | 152 | Next, on the command terminal go to `ngo-collaboration-using-blockchain` directory, and execute the below commands: 153 | ``` 154 | cd fabric-java-sdk-app 155 | mvn clean install 156 | ibmcloud cf push 157 | ``` 158 | Login to `IBM Cloud`. On the `Dashboard`, verify that an app `ngo-collaboration-java-app` is running fine. 159 | 160 | Make a note of this Fabric Java SDK client application's url. On IBM Cloud dashboard, click on the application. When application page opens, click on `Visit App URL`. Now make a note of the url, as shown on the browser, even if the page shows some error. If the url ends with a `/` then remove the trailing forward slash. This url should be provided in web application that interacts with this Fabric Java SDK client application. 161 | 162 | ## 4. Build and deploy webapp 163 | 164 | A web application is provided to perform various operations like `View Needs`, `Create Need`, `Pledge for a need` etc. Web appication code can be found under `webapp` directory. 165 | 166 | This web application invokes rest interfaces implemented in Fabric Java SDK client application as explained above. Hence the web application needs Fabric Java SDK client application url for rest invocations. 167 | 168 | Perform the following steps: 169 | 170 | - Update the Java application url, as noted in section [Build the client application based on Fabric Java SDK](#3-build-the-client-application-based-on-fabric-java-sdk) in `config.js` file, found in the root folder of web application. 171 | 172 | - On command prompt navigate to web application root folder. Run the command 173 | ``` 174 | npm install 175 | ``` 176 | This installs all the necessary libraries. 177 | 178 | - Next you will deploy the web application to IBM Cloud. Deploy the application to IBM Cloud using the command 179 | ``` 180 | ibmcloud cf push 181 | ``` 182 | Deployment might take a few minutes to complete. Ensure that there are no errors while deploying the application. 183 | 184 | 185 | ## 5. Analyze the Results 186 | 187 | Login to `IBM Cloud`. On the `Dashboard`, verify that an app `ngo-collaboration-webui` is running fine. Click on the web application entry. When application page opens, click on `Visit App URL`. Web application login page opens. 188 | 189 | Login usernames are `ngo1`, `ngo2`, `ngo3`, `ngo4`. Passwords are same as usernames. Login to the application using any login details. 190 | 191 | ![](images/webui-login.png) 192 | 193 | You will be presented with the tasks that you can perform. 194 | 195 | ![](images/webui-tasks.png) 196 | 197 | There are no needs available by default. So create one or more new needs. To create a new need click on `Create a New Need`. Enter need details. Note that the date format is always `dd-mm-yyyy`. 198 | 199 | ![](images/webui-create-need.png) 200 | 201 | Click on `Save` button to create need. A pop up message appears with the result of the create need request. Click `OK`. You can create more needs. Suggest you to create needs by logging in with different users so as to simulate a real scenario. Once done click on `Back to Home Page` button to return to tasks list. 202 | 203 | Click on `View Active Needs` to view the list of active needs, as shown in below image. Note that a need was already created while taking the below screen capture. For you there should be only one need listed for the first time you create a need. 204 | 205 | ![](images/webui-active-needs.png) 206 | 207 | Click on `Pledge` button to pledge a certian quantity of the need that was created. A pop up dialog asks for the quantity you want to pledge. Enter some quantity that is less than or equal to the remaining quantity for the need. 208 | 209 | ![](images/webui-pledge-qty.png) 210 | 211 | > Note: There are no validation done for the values entered. So, enter values that make sense. 212 | 213 | Click `OK`. You should get an alert message about the result of the pledge operation. Click `OK`. To refresh the data, click `Back to Home Page` and then again click `View Active Needs`. The pledged data should be updated. 214 | 215 | ![](images/webui-pledge-updated-qty.png) 216 | 217 | Similarly add a couple of more pledges, but login using different usernames for every pledge to simulate real scenario. After few more pledges are made, go to home page (dashboard) and click on `View Active Needs`. Click on the row of the need for which pledges were made. You should see details as shown in below image. 218 | 219 | ![](images/webui-pledges-for-a-need.png) 220 | 221 | Click `Back to Home Page` to go back to dashboard. 222 | 223 | `View Past Needs` shows all the needs whose `Expected Date of Fullfillment` is a past date as on current date. For us to have past needs, in the backend we added a need with a past date just to show the functionality here. You will have to wait till the date after the expected date of fullfill is over. Then click on `View Past Needs`. 224 | 225 | ![](images/webui-past-needs.png) 226 | 227 | We saw that needs can be created by different NGOs which is visible to all the NGOs in the network. Any NGO can pledge for the need which is captured in the network and whose details can also be viewed. NGOs can see past needs and their details as well. 228 | 229 | 230 | # Troubleshooting 231 | See [Debugging.md](./Debugging.md) 232 | 233 | 234 | # Learn More 235 | 236 | - [Track donations with Blockchain](https://developer.ibm.com/patterns/track-donations-blockchain/) 237 | - [Why NGOs need collaboration?](https://www.theguardian.com/global-development/poverty-matters/2012/mar/13/ngos-need-third-way-collaboration) 238 | - [Understand Business-NGO partnerships](https://blogs.worldbank.org/publicsphere/why-collaborate-three-frameworks-understand-business-ngo-partnerships) 239 | 240 | 241 | ## License 242 | 243 | This code pattern is licensed under the Apache Software License, Version 2. Separate third-party code objects invoked within this code pattern are licensed by their respective providers pursuant to their own separate licenses. Contributions are subject to the [Developer Certificate of Origin, Version 1.1 (DCO)](https://developercertificate.org/) and the [Apache Software License, Version 2](https://www.apache.org/licenses/LICENSE-2.0.txt). 244 | 245 | [Apache Software License (ASL) FAQ](https://www.apache.org/foundation/license-faq.html#WhatDoesItMEAN) 246 | -------------------------------------------------------------------------------- /blockchain-network-on-kubernetes/artifacts/chaincode/ngo_collaboration/ngo_collaboration.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /* 21 | * The smart contract for NGO Collaboration Solution 22 | */ 23 | 24 | package main 25 | 26 | /* Imports 27 | * utility libraries for formatting, handling bytes, reading and writing JSON, and string manipulation 28 | * 2 specific Hyperledger Fabric specific libraries for Smart Contracts 29 | */ 30 | import ( 31 | "bytes" 32 | "encoding/json" 33 | "fmt" 34 | "strconv" 35 | "strings" 36 | "unicode" 37 | 38 | "github.com/hyperledger/fabric/core/chaincode/shim" 39 | sc "github.com/hyperledger/fabric/protos/peer" 40 | ) 41 | 42 | // Define the Smart Contract structure 43 | type SmartContract struct { 44 | } 45 | 46 | // Define the need structure. Structure tags are used by encoding/json library 47 | type Need struct { 48 | NeedID string `json:"need_id"` 49 | CreatedBy string `json:"created_by"` 50 | CreatedDate string `json:"created_date"` 51 | NeedCategory string `json:"need_category"` 52 | RequiredQuantity int `json:"quantity"` 53 | PledgedQuantity int `json:"pledged"` 54 | PledgedIDs []string `json:"pledged_ids"` 55 | ExpectedFulfilmentDate string `json:"expected_fulfilment_date"` 56 | Status string `json:"need_status"` 57 | } 58 | 59 | // Define the Pledge structure 60 | type Pledge struct { 61 | PledgeID string `json:"pledge_id"` 62 | NeedID string `json:"need_id"` 63 | PledgedQuantity int `json:"pledged_quantity"` 64 | PledgedBy string `json:"pledged_by"` 65 | Status string `json:"status"` 66 | } 67 | 68 | /* 69 | * The Init method is called when the Smart Contract is instantiated by the blockchain network 70 | * Best practice is to have any Ledger initialization in separate function 71 | */ 72 | func (s *SmartContract) Init(APIstub shim.ChaincodeStubInterface) sc.Response { 73 | return shim.Success(nil) 74 | } 75 | 76 | /* 77 | * The Invoke method is called as a result of an application request to run the Smart Contract 78 | * The calling application program has also specified the particular smart contract function to be called, with arguments 79 | */ 80 | func (s *SmartContract) Invoke(APIstub shim.ChaincodeStubInterface) sc.Response { 81 | 82 | // Retrieve the requested Smart Contract function and arguments 83 | function, args := APIstub.GetFunctionAndParameters() 84 | // Route to the appropriate handler function to interact with the ledger appropriately 85 | if function == "queryNeed" { 86 | return s.queryNeed(APIstub, args) 87 | } else if function == "createNeed" { 88 | return s.createNeed(APIstub, args) 89 | } else if function == "createPledge" { 90 | return s.createPledge(APIstub, args) 91 | } else if function == "queryPledge" { 92 | return s.queryPledge(APIstub, args) 93 | } else if function == "queryAllActiveNeeds" { 94 | return s.queryAllActiveNeeds(APIstub, args) 95 | } else if function == "queryAllPastNeeds" { 96 | return s.queryAllPastNeeds(APIstub, args) 97 | } else if function == "queryAllPledgesForNeed" { 98 | return s.queryAllPledgesForNeed(APIstub, args) 99 | } else if function == "queryAllNeeds" { 100 | return s.queryAllNeeds(APIstub) 101 | } 102 | 103 | return shim.Error("Invalid Smart Contract function name.") 104 | } 105 | 106 | /* Function to query a specific need using a NeedID */ 107 | func (s *SmartContract) queryNeed(APIstub shim.ChaincodeStubInterface, args []string) sc.Response { 108 | 109 | if len(args) != 1 { 110 | return shim.Error("Incorrect number of arguments. Expecting 1") 111 | } 112 | 113 | needAsBytes, _ := APIstub.GetState(args[0]) 114 | return shim.Success(needAsBytes) 115 | } 116 | 117 | /* Function to create a new Need request and save it to ledger */ 118 | func (s *SmartContract) createNeed(APIstub shim.ChaincodeStubInterface, args []string) sc.Response { 119 | 120 | if len(args) != 6 { 121 | return shim.Error("Incorrect number of arguments. Expecting 6") 122 | } 123 | 124 | var requiredQuantity int 125 | requiredQuantity, _ = strconv.Atoi(args[4]) 126 | 127 | var need = Need{NeedID: args[0], CreatedBy: args[1], CreatedDate: args[2], NeedCategory: args[3], RequiredQuantity: requiredQuantity, PledgedQuantity: 0, ExpectedFulfilmentDate: args[5], Status: "Open"} 128 | 129 | needAsBytes, _ := json.Marshal(need) 130 | APIstub.PutState(args[0], needAsBytes) 131 | 132 | return shim.Success(nil) 133 | } 134 | 135 | /* Function to query a specific pledge by providing PledgeID */ 136 | func (s *SmartContract) queryPledge(APIstub shim.ChaincodeStubInterface, args []string) sc.Response { 137 | 138 | if len(args) != 1 { 139 | return shim.Error("Incorrect number of arguments. Expecting 1") 140 | } 141 | 142 | pledgeAsBytes, _ := APIstub.GetState(args[0]) 143 | return shim.Success(pledgeAsBytes) 144 | } 145 | 146 | /* Function to create a new Pledge request for a need and save it to ledger */ 147 | func (s *SmartContract) createPledge(APIstub shim.ChaincodeStubInterface, args []string) sc.Response { 148 | 149 | if len(args) != 5 { 150 | return shim.Error("Incorrect number of arguments. Expecting 5") 151 | } 152 | 153 | var existingVal int 154 | var newVal int 155 | var pledgedQuantity int 156 | pledgedQuantity, _ = strconv.Atoi(args[2]) 157 | 158 | needAsBytes, _ := APIstub.GetState(args[1]) 159 | need := Need{} 160 | 161 | json.Unmarshal(needAsBytes, &need) 162 | 163 | existingVal = need.PledgedQuantity 164 | newVal = existingVal + pledgedQuantity 165 | 166 | if newVal > need.RequiredQuantity { 167 | return shim.Error("Pledged quantity is more than required. Hence could not pledge.") 168 | } else { 169 | need.PledgedQuantity = existingVal + pledgedQuantity 170 | 171 | var pledge = Pledge{PledgeID: args[0], NeedID: args[1], PledgedQuantity: pledgedQuantity, PledgedBy: args[3], Status: args[4]} 172 | 173 | pledgeAsBytes, _ := json.Marshal(pledge) 174 | APIstub.PutState(args[0], pledgeAsBytes) 175 | 176 | need.PledgedIDs = append(need.PledgedIDs, args[0]) 177 | 178 | needAsBytes, _ = json.Marshal(need) 179 | APIstub.PutState(args[1], needAsBytes) 180 | 181 | return shim.Success(nil) 182 | } 183 | } 184 | 185 | /* 186 | * Function to query all Active Needs 187 | * Active Needs are the ones whose expected fulfillment date is not over wrt to the current date 188 | */ 189 | func (s *SmartContract) queryAllActiveNeeds(APIstub shim.ChaincodeStubInterface, args []string) sc.Response { 190 | 191 | if len(args) != 1 { 192 | return shim.Error("Incorrect number of arguments. Expecting 1") 193 | } 194 | 195 | startKey := "N1" 196 | endKey := "N99" 197 | 198 | var date1 []string 199 | var date2 []string 200 | var activeNeeds []Need 201 | 202 | activeNeeds = nil 203 | 204 | resultsIterator, err := APIstub.GetStateByRange(startKey, endKey) 205 | if err != nil { 206 | return shim.Error(err.Error()) 207 | } 208 | defer resultsIterator.Close() 209 | 210 | f := func(c rune) bool { 211 | return !unicode.IsLetter(c) && !unicode.IsNumber(c) 212 | } 213 | 214 | date2 = strings.FieldsFunc(args[0], f) 215 | date2Date, _ := strconv.Atoi(date2[0]) 216 | date2Month, _ := strconv.Atoi(date2[1]) 217 | date2Year, _ := strconv.Atoi(date2[2]) 218 | 219 | for resultsIterator.HasNext() { 220 | needDetails, err := resultsIterator.Next() 221 | if err != nil { 222 | return shim.Error(err.Error()) 223 | } 224 | //queryKeyAsStr := needDetails.Key 225 | queryValAsBytes := needDetails.Value 226 | 227 | var need Need 228 | json.Unmarshal(queryValAsBytes, &need) 229 | date1 = strings.FieldsFunc(need.ExpectedFulfilmentDate, f) 230 | 231 | date1Date, _ := strconv.Atoi(date1[0]) 232 | date1Month, _ := strconv.Atoi(date1[1]) 233 | date1Year, _ := strconv.Atoi(date1[2]) 234 | 235 | if date2Year > date1Year { 236 | fmt.Println("date2Year > date1Year") 237 | } else if date2Year < date1Year { // not considered here need.Status == "Open" 238 | activeNeeds = append(activeNeeds, need) 239 | } else if date2Year == date1Year && date2Month < date1Month { 240 | activeNeeds = append(activeNeeds, need) 241 | } else if date2Year == date1Year && date2Month == date1Month && date2Date <= date1Date { 242 | activeNeeds = append(activeNeeds, need) 243 | } 244 | } 245 | 246 | //change to array of bytes 247 | if activeNeeds != nil { 248 | everythingAsBytes, _ := json.Marshal(activeNeeds) 249 | return shim.Success(everythingAsBytes) 250 | } else { 251 | return shim.Success(nil) 252 | } 253 | } 254 | 255 | /* 256 | * Function to query all Past Needs 257 | * Past Needs are the ones whose expected fulfillment date is over wrt to the current date 258 | */ 259 | func (s *SmartContract) queryAllPastNeeds(APIstub shim.ChaincodeStubInterface, args []string) sc.Response { 260 | 261 | if len(args) != 1 { 262 | return shim.Error("Incorrect number of arguments. Expecting 1") 263 | } 264 | 265 | startKey := "N1" 266 | endKey := "N99" 267 | 268 | var date1 []string 269 | var date2 []string 270 | var pastNeeds []Need 271 | 272 | pastNeeds = nil 273 | resultsIterator, err := APIstub.GetStateByRange(startKey, endKey) 274 | if err != nil { 275 | return shim.Error(err.Error()) 276 | } 277 | defer resultsIterator.Close() 278 | 279 | f := func(c rune) bool { 280 | return !unicode.IsLetter(c) && !unicode.IsNumber(c) 281 | } 282 | 283 | date2 = strings.FieldsFunc(args[0], f) 284 | 285 | fmt.Println("PastNeeds: date2: ") 286 | fmt.Println(date2) 287 | 288 | date2Date, _ := strconv.Atoi(date2[0]) 289 | date2Month, _ := strconv.Atoi(date2[1]) 290 | date2Year, _ := strconv.Atoi(date2[2]) 291 | 292 | for resultsIterator.HasNext() { 293 | needDetails, err := resultsIterator.Next() 294 | if err != nil { 295 | return shim.Error(err.Error()) 296 | } 297 | //queryKeyAsStr := needDetails.Key 298 | queryValAsBytes := needDetails.Value 299 | 300 | var need Need 301 | json.Unmarshal(queryValAsBytes, &need) 302 | date1 = strings.FieldsFunc(need.ExpectedFulfilmentDate, f) 303 | fmt.Println("PastNeeds: date1: ") 304 | fmt.Println(date1) 305 | 306 | date1Date, _ := strconv.Atoi(date1[0]) 307 | date1Month, _ := strconv.Atoi(date1[1]) 308 | date1Year, _ := strconv.Atoi(date1[2]) 309 | 310 | if date2Year < date1Year { 311 | fmt.Println("date2Year < date1Year") 312 | } else if date2Year > date1Year { 313 | fmt.Println("date2Year > date1Year") 314 | pastNeeds = append(pastNeeds, need) 315 | } else if date2Year == date1Year && date2Month > date1Month { 316 | fmt.Println("date2Month > date1Month") 317 | pastNeeds = append(pastNeeds, need) 318 | } else if date2Year == date1Year && date2Month == date1Month && date2Date > date1Date { 319 | fmt.Println("date2Date > date1Date") 320 | pastNeeds = append(pastNeeds, need) 321 | } 322 | } 323 | 324 | //change to array of bytes 325 | if pastNeeds != nil { 326 | everythingAsBytes, _ := json.Marshal(pastNeeds) 327 | return shim.Success(everythingAsBytes) 328 | } else { 329 | return shim.Success(nil) 330 | } 331 | } 332 | 333 | /* Function to query All needs present in the system */ 334 | func (s *SmartContract) queryAllNeeds(APIstub shim.ChaincodeStubInterface) sc.Response { 335 | 336 | startKey := "N1" 337 | endKey := "N99" 338 | 339 | resultsIterator, err := APIstub.GetStateByRange(startKey, endKey) 340 | if err != nil { 341 | return shim.Error(err.Error()) 342 | } 343 | defer resultsIterator.Close() 344 | 345 | // buffer is a JSON array containing QueryResults 346 | var buffer bytes.Buffer 347 | buffer.WriteString("[") 348 | 349 | bArrayMemberAlreadyWritten := false 350 | for resultsIterator.HasNext() { 351 | queryResponse, err := resultsIterator.Next() 352 | if err != nil { 353 | return shim.Error(err.Error()) 354 | } 355 | // Add a comma before array members, suppress it for the first array member 356 | if bArrayMemberAlreadyWritten == true { 357 | buffer.WriteString(",") 358 | } 359 | buffer.WriteString("{\"Key\":") 360 | buffer.WriteString("\"") 361 | buffer.WriteString(queryResponse.Key) 362 | buffer.WriteString("\"") 363 | 364 | buffer.WriteString(", \"Record\":") 365 | // Record is a JSON object, so we write as-is 366 | buffer.WriteString(string(queryResponse.Value)) 367 | buffer.WriteString("}") 368 | bArrayMemberAlreadyWritten = true 369 | } 370 | buffer.WriteString("]") 371 | 372 | fmt.Printf("- queryAllNeeds:\n%s\n", buffer.String()) 373 | 374 | return shim.Success(buffer.Bytes()) 375 | } 376 | 377 | /* Function to query all Pledges details for a specific Need */ 378 | func (s *SmartContract) queryAllPledgesForNeed(APIstub shim.ChaincodeStubInterface, args []string) sc.Response { 379 | 380 | if len(args) != 1 { 381 | return shim.Error("Incorrect number of arguments. Expecting 1") 382 | } 383 | 384 | var pledges []Pledge 385 | var pledge1 Pledge 386 | needAsBytes, err := APIstub.GetState(args[0]) 387 | 388 | if err != nil { 389 | return shim.Error(err.Error()) 390 | } 391 | 392 | var need Need 393 | json.Unmarshal(needAsBytes, &need) 394 | 395 | var retrievedPledgedIDs []string 396 | retrievedPledgedIDs = need.PledgedIDs 397 | fmt.Printf("- retrievedPledgedIDs:\n%s\n", retrievedPledgedIDs) 398 | 399 | for i := 0; i < len(retrievedPledgedIDs); i++ { 400 | pledgedID := retrievedPledgedIDs[i] 401 | 402 | pledgeAsBytes, err2 := APIstub.GetState(pledgedID) 403 | 404 | if err2 != nil { 405 | return shim.Error(err.Error()) 406 | } 407 | json.Unmarshal(pledgeAsBytes, &pledge1) 408 | pledges = append(pledges, pledge1) 409 | } 410 | fmt.Printf("- queryAllPledgesForANeed:\n%s\n", pledges) 411 | 412 | //change to array of bytes 413 | allPledgesAsBytes, _ := json.Marshal(pledges) 414 | return shim.Success(allPledgesAsBytes) 415 | } 416 | 417 | // The main function is only relevant in unit test mode. Only included here for completeness. 418 | func main() { 419 | 420 | // Create a new Smart Contract 421 | err := shim.Start(new(SmartContract)) 422 | if err != nil { 423 | fmt.Printf("Error creating new Smart Contract: %s", err) 424 | } 425 | } 426 | -------------------------------------------------------------------------------- /blockchain-network-on-kubernetes/artifacts/configtx.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | ################################################################################ 3 | # 4 | # Section: Organizations 5 | # 6 | # - This section defines the different organizational identities which will 7 | # be referenced later in the configuration. 8 | # 9 | ################################################################################ 10 | Organizations: 11 | 12 | # SampleOrg defines an MSP using the sampleconfig. It should never be used 13 | # in production but may be used as a template for other definitions 14 | - &OrdererOrg 15 | # DefaultOrg defines the organization which is used in the sampleconfig 16 | # of the fabric.git development environment 17 | Name: OrdererOrg 18 | 19 | # ID to load the MSP definition as 20 | ID: OrdererMSP 21 | 22 | # MSPDir is the filesystem path which contains the MSP configuration 23 | MSPDir: crypto-config/ordererOrganizations/example.com/msp 24 | 25 | # AdminPrincipal dictates the type of principal used for an organization's Admins policy 26 | # Today, only the values of Role.ADMIN ad Role.MEMBER are accepted, which indicates a principal 27 | # of role type ADMIN and role type MEMBER respectively 28 | AdminPrincipal: Role.MEMBER 29 | 30 | - &Org1 31 | # DefaultOrg defines the organization which is used in the sampleconfig 32 | # of the fabric.git development environment 33 | Name: Org1MSP 34 | 35 | # ID to load the MSP definition as 36 | ID: Org1MSP 37 | 38 | MSPDir: crypto-config/peerOrganizations/org1.example.com/msp 39 | 40 | # AdminPrincipal dictates the type of principal used for an organization's Admins policy 41 | # Today, only the values of Role.ADMIN ad Role.MEMBER are accepted, which indicates a principal 42 | # of role type ADMIN and role type MEMBER respectively 43 | AdminPrincipal: Role.MEMBER 44 | 45 | AnchorPeers: 46 | # AnchorPeers defines the location of peers which can be used 47 | # for cross org gossip communication. Note, this value is only 48 | # encoded in the genesis block in the Application section context 49 | - Host: blockchain-org1peer1 50 | Port: 30110 51 | 52 | - &Org2 53 | # DefaultOrg defines the organization which is used in the sampleconfig 54 | # of the fabric.git development environment 55 | Name: Org2MSP 56 | 57 | # ID to load the MSP definition as 58 | ID: Org2MSP 59 | 60 | MSPDir: crypto-config/peerOrganizations/org2.example.com/msp 61 | 62 | # AdminPrincipal dictates the type of principal used for an organization's Admins policy 63 | # Today, only the values of Role.ADMIN ad Role.MEMBER are accepted, which indicates a principal 64 | # of role type ADMIN and role type MEMBER respectively 65 | AdminPrincipal: Role.MEMBER 66 | 67 | AnchorPeers: 68 | # AnchorPeers defines the location of peers which can be used 69 | # for cross org gossip communication. Note, this value is only 70 | # encoded in the genesis block in the Application section context 71 | - Host: blockchain-org2peer1 72 | Port: 30210 73 | 74 | ################################################################################ 75 | # 76 | # SECTION: Orderer 77 | # 78 | # - This section defines the values to encode into a config transaction or 79 | # genesis block for orderer related parameters 80 | # 81 | ################################################################################ 82 | Orderer: &OrdererDefaults 83 | 84 | # Orderer Type: The orderer implementation to start 85 | # Available types are "solo" and "kafka" 86 | OrdererType: solo 87 | 88 | Addresses: 89 | - blockchain-orderer:31010 90 | 91 | # Batch Timeout: The amount of time to wait before creating a batch 92 | BatchTimeout: 2s 93 | 94 | # Batch Size: Controls the number of messages batched into a block 95 | BatchSize: 96 | 97 | # Max Message Count: The maximum number of messages to permit in a batch 98 | MaxMessageCount: 10 99 | 100 | # Absolute Max Bytes: The absolute maximum number of bytes allowed for 101 | # the serialized messages in a batch. 102 | AbsoluteMaxBytes: 99 MB 103 | 104 | # Preferred Max Bytes: The preferred maximum number of bytes allowed for 105 | # the serialized messages in a batch. A message larger than the preferred 106 | # max bytes will result in a batch larger than preferred max bytes. 107 | PreferredMaxBytes: 512 KB 108 | 109 | Kafka: 110 | # Brokers: A list of Kafka brokers to which the orderer connects 111 | # NOTE: Use IP:port notation 112 | Brokers: 113 | - 127.0.0.1:9092 114 | 115 | # Organizations is the list of orgs which are defined as participants on 116 | # the orderer side of the network 117 | Organizations: 118 | 119 | ################################################################################ 120 | # 121 | # SECTION: Application 122 | # 123 | # - This section defines the values to encode into a config transaction or 124 | # genesis block for application related parameters 125 | # 126 | ################################################################################ 127 | Application: &ApplicationDefaults 128 | 129 | # Organizations is the list of orgs which are defined as participants on 130 | # the application side of the network 131 | Organizations: 132 | 133 | ################################################################################ 134 | # 135 | # Profile 136 | # 137 | # - Different configuration profiles may be encoded here to be specified 138 | # as parameters to the configtxgen tool 139 | # 140 | ################################################################################ 141 | Profiles: 142 | 143 | TwoOrgsOrdererGenesis: 144 | Orderer: 145 | <<: *OrdererDefaults 146 | Organizations: 147 | - *OrdererOrg 148 | Consortiums: 149 | SampleConsortium: 150 | Organizations: 151 | - *Org1 152 | - *Org2 153 | TwoOrgsChannel: 154 | Consortium: SampleConsortium 155 | Application: 156 | <<: *ApplicationDefaults 157 | Organizations: 158 | - *Org1 159 | - *Org2 -------------------------------------------------------------------------------- /blockchain-network-on-kubernetes/artifacts/crypto-config.yaml: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------- 2 | # "OrdererOrgs" - Definition of organizations managing orderer nodes 3 | # --------------------------------------------------------------------------- 4 | OrdererOrgs: 5 | # --------------------------------------------------------------------------- 6 | # Orderer 7 | # --------------------------------------------------------------------------- 8 | - Name: Orderer 9 | Domain: example.com 10 | # --------------------------------------------------------------------------- 11 | # "Specs" - See PeerOrgs below for complete description 12 | # --------------------------------------------------------------------------- 13 | Specs: 14 | - Hostname: orderer 15 | # --------------------------------------------------------------------------- 16 | # "PeerOrgs" - Definition of organizations managing peer nodes 17 | # --------------------------------------------------------------------------- 18 | PeerOrgs: 19 | # --------------------------------------------------------------------------- 20 | # Org1 21 | # --------------------------------------------------------------------------- 22 | - Name: Org1 23 | Domain: org1.example.com 24 | # --------------------------------------------------------------------------- 25 | # "Specs" 26 | # --------------------------------------------------------------------------- 27 | # Uncomment this section to enable the explicit definition of hosts in your 28 | # configuration. Most users will want to use Template, below 29 | # 30 | # Specs is an array of Spec entries. Each Spec entry consists of two fields: 31 | # - Hostname: (Required) The desired hostname, sans the domain. 32 | # - CommonName: (Optional) Specifies the template or explicit override for 33 | # the CN. By default, this is the template: 34 | # 35 | # "{{.Hostname}}.{{.Domain}}" 36 | # 37 | # which obtains its values from the Spec.Hostname and 38 | # Org.Domain, respectively. 39 | # --------------------------------------------------------------------------- 40 | # Specs: 41 | # - Hostname: foo # implicitly "foo.org1.example.com" 42 | # CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above 43 | # - Hostname: bar 44 | # - Hostname: baz 45 | # --------------------------------------------------------------------------- 46 | # "Template" 47 | # --------------------------------------------------------------------------- 48 | # Allows for the definition of 1 or more hosts that are created sequentially 49 | # from a template. By default, this looks like "peer%d" from 0 to Count-1. 50 | # You may override the number of nodes (Count), the starting index (Start) 51 | # or the template used to construct the name (Hostname). 52 | # 53 | # Note: Template and Specs are not mutually exclusive. You may define both 54 | # sections and the aggregate nodes will be created for you. Take care with 55 | # name collisions 56 | # --------------------------------------------------------------------------- 57 | Template: 58 | Count: 2 59 | # Start: 5 60 | # Hostname: {{.Prefix}}{{.Index}} # default 61 | # --------------------------------------------------------------------------- 62 | # "Users" 63 | # --------------------------------------------------------------------------- 64 | # Count: The number of user accounts _in addition_ to Admin 65 | # --------------------------------------------------------------------------- 66 | Users: 67 | Count: 1 68 | # --------------------------------------------------------------------------- 69 | # Org2: See "Org1" for full specification 70 | # --------------------------------------------------------------------------- 71 | - Name: Org2 72 | Domain: org2.example.com 73 | Template: 74 | Count: 2 75 | Users: 76 | Count: 1 77 | -------------------------------------------------------------------------------- /blockchain-network-on-kubernetes/configFiles/blockchain-services.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: blockchain-ca1 6 | labels: 7 | run: blockchain-ca1 8 | spec: 9 | type: NodePort 10 | selector: 11 | name: ca1 12 | ports: 13 | - protocol: TCP 14 | nodePort: 30054 15 | targetPort: 7054 16 | port: 30054 17 | name: grpc 18 | --- 19 | apiVersion: v1 20 | kind: Service 21 | metadata: 22 | name: blockchain-ca2 23 | labels: 24 | run: blockchain-ca2 25 | spec: 26 | type: NodePort 27 | selector: 28 | name: ca2 29 | ports: 30 | - protocol: TCP 31 | nodePort: 30064 32 | targetPort: 7064 33 | port: 30064 34 | name: grpc 35 | --- 36 | apiVersion: v1 37 | kind: Service 38 | metadata: 39 | name: blockchain-orderer 40 | labels: 41 | run: blockchain-orderer 42 | spec: 43 | type: NodePort 44 | selector: 45 | name: orderer 46 | ports: 47 | - protocol: TCP 48 | nodePort: 31010 49 | targetPort: 31010 50 | port: 31010 51 | name: grpc 52 | --- 53 | apiVersion: v1 54 | kind: Service 55 | metadata: 56 | name: blockchain-org1peer1 57 | labels: 58 | run: blockchain-org1peer1 59 | spec: 60 | type: NodePort 61 | selector: 62 | name: org1peer1 63 | ports: 64 | - protocol: TCP 65 | nodePort: 30110 66 | targetPort: 30110 67 | port: 30110 68 | name: grpc 69 | - protocol: TCP 70 | nodePort: 30111 71 | targetPort: 30111 72 | port: 30111 73 | name: events 74 | --- 75 | apiVersion: v1 76 | kind: Service 77 | metadata: 78 | name: blockchain-org1peer2 79 | labels: 80 | run: blockchain-org1peer2 81 | spec: 82 | type: NodePort 83 | selector: 84 | name: org1peer2 85 | ports: 86 | - protocol: TCP 87 | nodePort: 30210 88 | targetPort: 30210 89 | port: 30210 90 | name: grpc 91 | - protocol: TCP 92 | nodePort: 30211 93 | targetPort: 30211 94 | port: 30211 95 | name: events 96 | 97 | --- 98 | apiVersion: v1 99 | kind: Service 100 | metadata: 101 | name: blockchain-org2peer1 102 | labels: 103 | run: blockchain-org2peer1 104 | spec: 105 | type: NodePort 106 | selector: 107 | name: org2peer1 108 | ports: 109 | - protocol: TCP 110 | nodePort: 30310 111 | targetPort: 30310 112 | port: 30310 113 | name: grpc 114 | - protocol: TCP 115 | nodePort: 30311 116 | targetPort: 30311 117 | port: 30311 118 | name: events 119 | 120 | --- 121 | apiVersion: v1 122 | kind: Service 123 | metadata: 124 | name: blockchain-org2peer2 125 | labels: 126 | run: blockchain-org2peer2 127 | spec: 128 | type: NodePort 129 | selector: 130 | name: org2peer2 131 | ports: 132 | - protocol: TCP 133 | nodePort: 30410 134 | targetPort: 30410 135 | port: 30410 136 | name: grpc 137 | - protocol: TCP 138 | nodePort: 30411 139 | targetPort: 30411 140 | port: 30411 141 | name: events -------------------------------------------------------------------------------- /blockchain-network-on-kubernetes/configFiles/chaincode_install.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: chaincodeinstall 6 | spec: 7 | backoffLimit: 1 8 | template: 9 | metadata: 10 | name: chaincodeinstall 11 | spec: 12 | restartPolicy: "Never" 13 | volumes: 14 | - name: sharedvolume 15 | persistentVolumeClaim: 16 | claimName: shared-pvc 17 | containers: 18 | - name: chaincodeinstall1 19 | image: hyperledger/fabric-tools:1.4.0 20 | imagePullPolicy: Always 21 | command: ["sh", "-c", "echo $GOPATH; cp -r /shared/artifacts/chaincode $GOPATH/src/; ls $GOPATH/src; peer chaincode install -n ${CHAINCODE_NAME} -v ${CHAINCODE_VERSION} -p ngo_collaboration/"] 22 | env: 23 | - name: CHAINCODE_NAME 24 | value: "ngo" 25 | - name: CHAINCODE_VERSION 26 | value: "1.0" 27 | - name: FABRIC_CFG_PATH 28 | value: /etc/hyperledger/fabric 29 | - name: CORE_PEER_MSPCONFIGPATH 30 | value: /shared/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp 31 | - name: CORE_PEER_LOCALMSPID 32 | value: Org1MSP 33 | - name: CORE_PEER_ADDRESS 34 | value: blockchain-org1peer1:30110 35 | - name: GODEBUG 36 | value: "netdns=go" 37 | volumeMounts: 38 | - mountPath: /shared 39 | name: sharedvolume 40 | 41 | - name: chaincodeinstall2 42 | image: hyperledger/fabric-tools:1.4.0 43 | imagePullPolicy: Always 44 | command: ["sh", "-c", "echo $GOPATH; cp -r /shared/artifacts/chaincode $GOPATH/src/; ls $GOPATH/src; peer chaincode install -n ${CHAINCODE_NAME} -v ${CHAINCODE_VERSION} -p ngo_collaboration/"] 45 | env: 46 | - name: CHAINCODE_NAME 47 | value: "ngo" 48 | - name: CHAINCODE_VERSION 49 | value: "1.0" 50 | - name: FABRIC_CFG_PATH 51 | value: /etc/hyperledger/fabric 52 | - name: CORE_PEER_MSPCONFIGPATH 53 | value: /shared/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp 54 | - name: CORE_PEER_LOCALMSPID 55 | value: Org1MSP 56 | - name: CORE_PEER_ADDRESS 57 | value: blockchain-org1peer2:30210 58 | - name: GODEBUG 59 | value: "netdns=go" 60 | volumeMounts: 61 | - mountPath: /shared 62 | name: sharedvolume 63 | 64 | - name: chaincodeinstall3 65 | image: hyperledger/fabric-tools:1.4.0 66 | imagePullPolicy: Always 67 | command: ["sh", "-c", "echo $GOPATH; cp -r /shared/artifacts/chaincode $GOPATH/src/; ls $GOPATH/src; peer chaincode install -n ${CHAINCODE_NAME} -v ${CHAINCODE_VERSION} -p ngo_collaboration/"] 68 | env: 69 | - name: CHAINCODE_NAME 70 | value: "ngo" 71 | - name: CHAINCODE_VERSION 72 | value: "1.0" 73 | - name: FABRIC_CFG_PATH 74 | value: /etc/hyperledger/fabric 75 | - name: CORE_PEER_MSPCONFIGPATH 76 | value: /shared/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp 77 | - name: CORE_PEER_LOCALMSPID 78 | value: Org2MSP 79 | - name: CORE_PEER_ADDRESS 80 | value: blockchain-org2peer1:30310 81 | - name: GODEBUG 82 | value: "netdns=go" 83 | volumeMounts: 84 | - mountPath: /shared 85 | name: sharedvolume 86 | 87 | - name: chaincodeinstall4 88 | image: hyperledger/fabric-tools:1.4.0 89 | imagePullPolicy: Always 90 | command: ["sh", "-c", "echo $GOPATH; cp -r /shared/artifacts/chaincode $GOPATH/src/; ls $GOPATH/src; peer chaincode install -n ${CHAINCODE_NAME} -v ${CHAINCODE_VERSION} -p ngo_collaboration/"] 91 | env: 92 | - name: CHAINCODE_NAME 93 | value: "ngo" 94 | - name: CHAINCODE_VERSION 95 | value: "1.0" 96 | - name: FABRIC_CFG_PATH 97 | value: /etc/hyperledger/fabric 98 | - name: CORE_PEER_MSPCONFIGPATH 99 | value: /shared/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp 100 | - name: CORE_PEER_LOCALMSPID 101 | value: Org2MSP 102 | - name: CORE_PEER_ADDRESS 103 | value: blockchain-org2peer2:30410 104 | - name: GODEBUG 105 | value: "netdns=go" 106 | volumeMounts: 107 | - mountPath: /shared 108 | name: sharedvolume 109 | -------------------------------------------------------------------------------- /blockchain-network-on-kubernetes/configFiles/chaincode_instantiate.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: chaincodeinstantiate 6 | spec: 7 | backoffLimit: 1 8 | template: 9 | metadata: 10 | name: chaincodeinstantiate 11 | spec: 12 | restartPolicy: "Never" 13 | volumes: 14 | - name: sharedvolume 15 | persistentVolumeClaim: 16 | claimName: shared-pvc 17 | 18 | containers: 19 | - name: chaincodeinstantiate 20 | image: hyperledger/fabric-tools:1.4.0 21 | imagePullPolicy: Always 22 | command: ["sh", "-c", "ls ${CHAINCODE_NAME}; peer chaincode instantiate -o blockchain-orderer:31010 -C ${CHANNEL_NAME} -n ${CHAINCODE_NAME} -v ${CHAINCODE_VERSION} -c '{\"Args\":[\"init\",\"\"]}'"] 23 | env: 24 | - name: CHANNEL_NAME 25 | value: channel1 26 | - name: CHAINCODE_NAME 27 | value: "ngo" 28 | - name: CHAINCODE_VERSION 29 | value: "1.0" 30 | - name: FABRIC_CFG_PATH 31 | value: /etc/hyperledger/fabric 32 | - name: CORE_PEER_MSPCONFIGPATH 33 | value: /shared/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp 34 | - name: CORE_PEER_LOCALMSPID 35 | value: Org1MSP 36 | - name: CORE_PEER_ADDRESS 37 | value: blockchain-org1peer1:30110 38 | - name: GODEBUG 39 | value: "netdns=go" 40 | volumeMounts: 41 | - mountPath: /shared 42 | name: sharedvolume 43 | -------------------------------------------------------------------------------- /blockchain-network-on-kubernetes/configFiles/copyArtifactsJob.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: copyartifacts 6 | spec: 7 | backoffLimit: 1 8 | template: 9 | metadata: 10 | name: copyartifacts 11 | spec: 12 | restartPolicy: "Never" 13 | volumes: 14 | - name: sharedvolume 15 | persistentVolumeClaim: 16 | claimName: shared-pvc 17 | - name: dockersocket 18 | hostPath: 19 | path: /var/run/docker.sock 20 | containers: 21 | - name: copyartifacts 22 | image: alpine:3.7 23 | imagePullPolicy: Always 24 | command: ["sh", "-c", "ls -l /shared; rm -rf /shared/*; ls -l /shared; while [ ! -d /shared/artifacts ]; do echo Waiting for artifacts to be copied; sleep 2; done; sleep 10; ls -l /shared/artifacts; "] 25 | volumeMounts: 26 | - mountPath: /shared 27 | name: sharedvolume 28 | -------------------------------------------------------------------------------- /blockchain-network-on-kubernetes/configFiles/createVolume-paid.yaml: -------------------------------------------------------------------------------- 1 | kind: PersistentVolumeClaim 2 | apiVersion: v1 3 | metadata: 4 | name: shared-pvc 5 | labels: 6 | app: blockchain 7 | spec: 8 | accessModes: 9 | - ReadWriteMany 10 | resources: 11 | requests: 12 | storage: 20Gi 13 | storageClassName: "ibmc-file-bronze" 14 | -------------------------------------------------------------------------------- /blockchain-network-on-kubernetes/configFiles/createVolume.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: PersistentVolume 3 | apiVersion: v1 4 | metadata: 5 | name: shared-pv 6 | labels: 7 | type: local 8 | name: sharedvolume 9 | spec: 10 | capacity: 11 | storage: 1Gi 12 | accessModes: 13 | - ReadWriteMany 14 | hostPath: 15 | path: "/tmp" 16 | 17 | --- 18 | kind: PersistentVolumeClaim 19 | apiVersion: v1 20 | metadata: 21 | name: shared-pvc 22 | spec: 23 | accessModes: 24 | - ReadWriteMany 25 | resources: 26 | requests: 27 | storage: 1Gi 28 | storageClassName: "" 29 | selector: 30 | matchLabels: 31 | name: sharedvolume 32 | -------------------------------------------------------------------------------- /blockchain-network-on-kubernetes/configFiles/create_channel.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: createchannel 6 | spec: 7 | backoffLimit: 1 8 | template: 9 | metadata: 10 | name: createchannel 11 | spec: 12 | restartPolicy: "Never" 13 | volumes: 14 | - name: sharedvolume 15 | persistentVolumeClaim: 16 | claimName: shared-pvc 17 | containers: 18 | - name: createchanneltx 19 | image: hyperledger/fabric-tools:1.4.0 20 | imagePullPolicy: Always 21 | command: ["sh", "-c", "cd /shared && pwd && ls && export FABRIC_CFG_PATH=$PWD && configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ${CHANNEL_NAME}.tx -channelID ${CHANNEL_NAME} && touch /shared/status_channeltx_complete "] 22 | env: 23 | - name: CHANNEL_NAME 24 | value: channel1 25 | - name: GODEBUG 26 | value: "netdns=go" 27 | volumeMounts: 28 | - mountPath: /shared 29 | name: sharedvolume 30 | 31 | - name: createchannel 32 | image: hyperledger/fabric-peer:1.4.0 33 | imagePullPolicy: Always 34 | command: ["sh", "-c", "while [ ! -f /shared/status_channeltx_complete ]; do echo Waiting for channeltx; sleep 2; done; peer channel create -o ${ORDERER_URL} -c ${CHANNEL_NAME} -f /shared/${CHANNEL_NAME}.tx && rm /shared/status_channeltx_complete && touch /shared/status_channelcreate_complete"] 35 | env: 36 | - name: CHANNEL_NAME 37 | value: channel1 38 | - name: ORDERER_URL 39 | value: blockchain-orderer:31010 40 | - name: CORE_PEER_ADDRESSAUTODETECT 41 | value: "false" 42 | - name: CORE_PEER_NETWORKID 43 | value: nid1 44 | - name: CORE_PEER_LOCALMSPID 45 | value: Org1MSP 46 | - name: CORE_PEER_MSPCONFIGPATH 47 | value: /shared/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp/ 48 | - name: FABRIC_LOGGING_SPEC 49 | value: debug 50 | - name: FABRIC_CFG_PATH 51 | value: /etc/hyperledger/fabric 52 | - name: GODEBUG 53 | value: "netdns=go" 54 | volumeMounts: 55 | - mountPath: /shared 56 | name: sharedvolume 57 | -------------------------------------------------------------------------------- /blockchain-network-on-kubernetes/configFiles/docker-volume.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: PersistentVolume 3 | apiVersion: v1 4 | metadata: 5 | name: docker-pv 6 | labels: 7 | type: local 8 | name: dockervolume 9 | spec: 10 | capacity: 11 | storage: 10Gi 12 | accessModes: 13 | - ReadWriteMany 14 | hostPath: 15 | path: "/tmp-docker-pv" 16 | 17 | --- 18 | kind: PersistentVolumeClaim 19 | apiVersion: v1 20 | metadata: 21 | name: docker-pvc 22 | spec: 23 | accessModes: 24 | - ReadWriteMany 25 | resources: 26 | requests: 27 | storage: 10Gi 28 | storageClassName: "" 29 | selector: 30 | matchLabels: 31 | name: dockervolume -------------------------------------------------------------------------------- /blockchain-network-on-kubernetes/configFiles/docker.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: docker 6 | labels: 7 | run: docker 8 | spec: 9 | selector: 10 | name: docker 11 | ports: 12 | - protocol: TCP 13 | targetPort: 2375 14 | port: 2375 15 | --- 16 | apiVersion: extensions/v1beta1 17 | kind: Deployment 18 | metadata: 19 | name: docker-dind 20 | spec: 21 | replicas: 1 22 | template: 23 | metadata: 24 | labels: 25 | name: docker 26 | spec: 27 | volumes: 28 | - name: dockervolume 29 | persistentVolumeClaim: 30 | claimName: docker-pvc 31 | containers: 32 | - name: docker 33 | securityContext: 34 | privileged: true 35 | image: "docker:stable-dind" 36 | ports: 37 | - containerPort: 2375 38 | volumeMounts: 39 | - mountPath: /var/lib/docker 40 | name: dockervolume -------------------------------------------------------------------------------- /blockchain-network-on-kubernetes/configFiles/generateArtifactsJob.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: utils 6 | spec: 7 | backoffLimit: 1 8 | template: 9 | metadata: 10 | name: utils 11 | spec: 12 | restartPolicy: "Never" 13 | volumes: 14 | - name: sharedvolume 15 | persistentVolumeClaim: 16 | claimName: shared-pvc 17 | - name: dockersocket 18 | hostPath: 19 | path: /var/run/docker.sock 20 | containers: 21 | - name: cryptogen 22 | image: hyperledger/fabric-tools:1.4.0 23 | imagePullPolicy: Always 24 | command: ["sh", "-c", "echo 'Cryptogen Starts'; ls -l /shared/artifacts; while [ ! -d /shared/artifacts ]; do echo Waiting for configFiles; sleep 1; done; cryptogen generate --config /shared/artifacts/crypto-config.yaml && cp -r crypto-config /shared/ && for file in $(find /shared/ -iname *_sk); do echo $file; dir=$(dirname $file); echo ${dir}; mv ${dir}/*_sk ${dir}/key.pem; done && find /shared -type d | xargs chmod a+rx && find /shared -type f | xargs chmod a+r && touch /shared/status_cryptogen_complete;"] 25 | volumeMounts: 26 | - mountPath: /shared 27 | name: sharedvolume 28 | - name: configtxgen 29 | image: hyperledger/fabric-tools:1.4.0 30 | imagePullPolicy: Always 31 | command: ["sh", "-c", "echo 'Configtxgen Starts'; ls -l /shared; sleep 1 && while [ ! -f /shared/status_cryptogen_complete ]; do echo Waiting for cryptogen; sleep 1; done; cp /shared/artifacts/configtx.yaml /shared/; cd /shared/; export FABRIC_CFG_PATH=$PWD; configtxgen -profile TwoOrgsOrdererGenesis -outputBlock genesis.block && find /shared -type d | xargs chmod a+rx && find /shared -type f | xargs chmod a+r && touch /shared/status_configtxgen_complete && rm /shared/status_cryptogen_complete;"] 32 | volumeMounts: 33 | - mountPath: /shared 34 | name: sharedvolume 35 | 36 | -------------------------------------------------------------------------------- /blockchain-network-on-kubernetes/configFiles/join_channel.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: joinchannel 6 | spec: 7 | backoffLimit: 1 8 | template: 9 | metadata: 10 | name: joinchannel 11 | spec: 12 | restartPolicy: "Never" 13 | volumes: 14 | - name: sharedvolume 15 | persistentVolumeClaim: 16 | claimName: shared-pvc 17 | containers: 18 | - name: joinchannel1 19 | image: hyperledger/fabric-peer:1.4.0 20 | imagePullPolicy: Always 21 | command: ["sh", "-c", "peer channel fetch newest -o ${ORDERER_URL} -c ${CHANNEL_NAME} && peer channel join -b ${CHANNEL_NAME}_newest.block "] 22 | env: 23 | - name: CHANNEL_NAME 24 | value: channel1 25 | - name: CORE_PEER_NETWORKID 26 | value: nid1 27 | - name: ORDERER_URL 28 | value: blockchain-orderer:31010 29 | - name: CORE_PEER_ADDRESS 30 | value: blockchain-org1peer1:30110 31 | - name: CORE_PEER_LOCALMSPID 32 | value: Org1MSP 33 | - name: CORE_PEER_MSPID 34 | value: Org1MSP 35 | - name: FABRIC_LOGGING_SPEC 36 | value: debug 37 | - name: CORE_PEER_MSPCONFIGPATH 38 | value: /shared/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp 39 | - name: FABRIC_CFG_PATH 40 | value: /etc/hyperledger/fabric 41 | - name: GODEBUG 42 | value: "netdns=go" 43 | volumeMounts: 44 | - mountPath: /shared 45 | name: sharedvolume 46 | 47 | - name: joinchannel2 48 | image: hyperledger/fabric-peer:1.4.0 49 | imagePullPolicy: Always 50 | command: ["sh", "-c", "peer channel fetch newest -o ${ORDERER_URL} -c ${CHANNEL_NAME} && peer channel join -b ${CHANNEL_NAME}_newest.block "] 51 | env: 52 | - name: CHANNEL_NAME 53 | value: channel1 54 | - name: CORE_PEER_NETWORKID 55 | value: nid1 56 | - name: ORDERER_URL 57 | value: blockchain-orderer:31010 58 | - name: CORE_PEER_ADDRESS 59 | value: blockchain-org1peer2:30210 60 | - name: CORE_PEER_LOCALMSPID 61 | value: Org1MSP 62 | - name: CORE_PEER_MSPID 63 | value: Org1MSP 64 | - name: FABRIC_LOGGING_SPEC 65 | value: debug 66 | - name: CORE_PEER_MSPCONFIGPATH 67 | value: /shared/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp 68 | - name: FABRIC_CFG_PATH 69 | value: /etc/hyperledger/fabric 70 | - name: GODEBUG 71 | value: "netdns=go" 72 | volumeMounts: 73 | - mountPath: /shared 74 | name: sharedvolume 75 | 76 | - name: joinchannel3 77 | image: hyperledger/fabric-peer:1.4.0 78 | imagePullPolicy: Always 79 | command: ["sh", "-c", "peer channel fetch newest -o ${ORDERER_URL} -c ${CHANNEL_NAME} && peer channel join -b ${CHANNEL_NAME}_newest.block "] 80 | env: 81 | - name: CHANNEL_NAME 82 | value: channel1 83 | - name: CORE_PEER_NETWORKID 84 | value: nid1 85 | - name: ORDERER_URL 86 | value: blockchain-orderer:31010 87 | - name: CORE_PEER_ADDRESS 88 | value: blockchain-org2peer1:30310 89 | - name: CORE_PEER_LOCALMSPID 90 | value: Org2MSP 91 | - name: CORE_PEER_MSPID 92 | value: Org2MSP 93 | - name: FABRIC_LOGGING_SPEC 94 | value: debug 95 | - name: CORE_PEER_MSPCONFIGPATH 96 | value: /shared/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp 97 | - name: FABRIC_CFG_PATH 98 | value: /etc/hyperledger/fabric 99 | - name: GODEBUG 100 | value: "netdns=go" 101 | volumeMounts: 102 | - mountPath: /shared 103 | name: sharedvolume 104 | 105 | - name: joinchannel4 106 | image: hyperledger/fabric-peer:1.4.0 107 | imagePullPolicy: Always 108 | command: ["sh", "-c", "peer channel fetch newest -o ${ORDERER_URL} -c ${CHANNEL_NAME} && peer channel join -b ${CHANNEL_NAME}_newest.block "] 109 | env: 110 | - name: CHANNEL_NAME 111 | value: channel1 112 | - name: CORE_PEER_NETWORKID 113 | value: nid1 114 | - name: ORDERER_URL 115 | value: blockchain-orderer:31010 116 | - name: CORE_PEER_ADDRESS 117 | value: blockchain-org2peer2:30410 118 | - name: CORE_PEER_LOCALMSPID 119 | value: Org2MSP 120 | - name: CORE_PEER_MSPID 121 | value: Org2MSP 122 | - name: FABRIC_LOGGING_SPEC 123 | value: debug 124 | - name: CORE_PEER_MSPCONFIGPATH 125 | value: /shared/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp 126 | - name: FABRIC_CFG_PATH 127 | value: /etc/hyperledger/fabric 128 | - name: GODEBUG 129 | value: "netdns=go" 130 | volumeMounts: 131 | - mountPath: /shared 132 | name: sharedvolume 133 | 134 | -------------------------------------------------------------------------------- /blockchain-network-on-kubernetes/deleteNetwork.sh: -------------------------------------------------------------------------------- 1 | 2 | KUBECONFIG_FOLDER=${PWD}/configFiles 3 | 4 | kubectl delete -f ${KUBECONFIG_FOLDER}/chaincode_instantiate.yaml 5 | kubectl delete -f ${KUBECONFIG_FOLDER}/chaincode_install.yaml 6 | 7 | kubectl delete -f ${KUBECONFIG_FOLDER}/join_channel.yaml 8 | kubectl delete -f ${KUBECONFIG_FOLDER}/create_channel.yaml 9 | 10 | kubectl delete --ignore-not-found=true -f ${KUBECONFIG_FOLDER}/docker.yaml 11 | 12 | kubectl delete -f ${KUBECONFIG_FOLDER}/peersDeployment.yaml 13 | kubectl delete -f ${KUBECONFIG_FOLDER}/blockchain-services.yaml 14 | 15 | kubectl delete -f ${KUBECONFIG_FOLDER}/generateArtifactsJob.yaml 16 | kubectl delete -f ${KUBECONFIG_FOLDER}/copyArtifactsJob.yaml 17 | 18 | kubectl delete -f ${KUBECONFIG_FOLDER}/createVolume.yaml 19 | kubectl delete --ignore-not-found=true -f ${KUBECONFIG_FOLDER}/docker-volume.yaml 20 | 21 | sleep 15 22 | 23 | echo -e "\npv:" 24 | kubectl get pv 25 | echo -e "\npvc:" 26 | kubectl get pvc 27 | echo -e "\njobs:" 28 | kubectl get jobs 29 | echo -e "\ndeployments:" 30 | kubectl get deployments 31 | echo -e "\nservices:" 32 | kubectl get services 33 | echo -e "\npods:" 34 | kubectl get pods 35 | 36 | echo -e "\nNetwork Deleted!!\n" 37 | 38 | -------------------------------------------------------------------------------- /blockchain-network-on-kubernetes/setup_blockchainNetwork_v1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -d "${PWD}/configFiles" ]; then 4 | KUBECONFIG_FOLDER=${PWD}/configFiles 5 | else 6 | echo "Configuration files are not found." 7 | exit 8 | fi 9 | 10 | # Create Docker deployment 11 | if [ "$(cat configFiles/peersDeployment.yaml | grep -c tcp://docker:2375)" != "0" ]; then 12 | echo "peersDeployment.yaml file was configured to use Docker in a container." 13 | echo "Creating Docker deployment" 14 | 15 | kubectl create -f ${KUBECONFIG_FOLDER}/docker-volume.yaml 16 | kubectl create -f ${KUBECONFIG_FOLDER}/docker.yaml 17 | sleep 5 18 | 19 | dockerPodStatus=$(kubectl get pods --selector=name=docker --output=jsonpath={.items..phase}) 20 | 21 | while [ "${dockerPodStatus}" != "Running" ]; do 22 | echo "Wating for Docker container to run. Current status of Docker is ${dockerPodStatus}" 23 | sleep 5; 24 | if [ "${dockerPodStatus}" == "Error" ]; then 25 | echo "There is an error in the Docker pod. Please check logs." 26 | exit 1 27 | fi 28 | dockerPodStatus=$(kubectl get pods --selector=name=docker --output=jsonpath={.items..phase}) 29 | done 30 | fi 31 | 32 | # Creating Persistant Volume 33 | echo -e "\nCreating volume" 34 | if [ "$(kubectl get pvc | grep shared-pvc | awk '{print $2}')" != "Bound" ]; then 35 | echo "The Persistant Volume does not seem to exist or is not bound" 36 | echo "Creating Persistant Volume" 37 | 38 | if [ "$1" == "--paid" ]; then 39 | echo "You passed argument --paid. Make sure you have an IBM Cloud Kubernetes - Standard tier. Else, remove --paid option" 40 | echo "Running: kubectl create -f ${KUBECONFIG_FOLDER}/createVolume-paid.yaml" 41 | kubectl create -f ${KUBECONFIG_FOLDER}/createVolume-paid.yaml 42 | sleep 5 43 | else 44 | echo "Running: kubectl create -f ${KUBECONFIG_FOLDER}/createVolume.yaml" 45 | kubectl create -f ${KUBECONFIG_FOLDER}/createVolume.yaml 46 | sleep 5 47 | fi 48 | 49 | if [ "kubectl get pvc | grep shared-pvc | awk '{print $3}'" != "shared-pv" ]; then 50 | echo "Success creating Persistant Volume" 51 | else 52 | echo "Failed to create Persistant Volume" 53 | fi 54 | else 55 | echo "The Persistant Volume exists, not creating again" 56 | fi 57 | 58 | # Copy the required files(configtx.yaml, cruypto-config.yaml, sample chaincode etc.) into volume 59 | echo -e "\nCreating Copy artifacts job." 60 | echo "Running: kubectl create -f ${KUBECONFIG_FOLDER}/copyArtifactsJob.yaml" 61 | kubectl create -f ${KUBECONFIG_FOLDER}/copyArtifactsJob.yaml 62 | 63 | pod=$(kubectl get pods --selector=job-name=copyartifacts --output=jsonpath={.items..metadata.name}) 64 | 65 | podSTATUS=$(kubectl get pods --selector=job-name=copyartifacts --output=jsonpath={.items..phase}) 66 | 67 | while [ "${podSTATUS}" != "Running" ]; do 68 | echo "Wating for container of copy artifact pod to run. Current status of ${pod} is ${podSTATUS}" 69 | sleep 5; 70 | if [ "${podSTATUS}" == "Error" ]; then 71 | echo "There is an error in copyartifacts job. Please check logs." 72 | exit 1 73 | fi 74 | podSTATUS=$(kubectl get pods --selector=job-name=copyartifacts --output=jsonpath={.items..phase}) 75 | done 76 | 77 | echo -e "${pod} is now ${podSTATUS}" 78 | echo -e "\nStarting to copy artifacts in persistent volume." 79 | 80 | #fix for this script to work on icp and ICS 81 | kubectl cp ./artifacts $pod:/shared/ 82 | 83 | echo "Waiting for 10 more seconds for copying artifacts to avoid any network delay" 84 | sleep 10 85 | JOBSTATUS=$(kubectl get jobs |grep "copyartifacts" |awk '{print $3}') 86 | while [ "${JOBSTATUS}" != "1" ]; do 87 | echo "Waiting for copyartifacts job to complete" 88 | sleep 1; 89 | PODSTATUS=$(kubectl get pods | grep "copyartifacts" | awk '{print $3}') 90 | if [ "${PODSTATUS}" == "Error" ]; then 91 | echo "There is an error in copyartifacts job. Please check logs." 92 | exit 1 93 | fi 94 | JOBSTATUS=$(kubectl get jobs |grep "copyartifacts" |awk '{print $3}') 95 | done 96 | echo "Copy artifacts job completed" 97 | 98 | 99 | # Generate Network artifacts using configtx.yaml and crypto-config.yaml 100 | echo -e "\nGenerating the required artifacts for Blockchain network" 101 | echo "Running: kubectl create -f ${KUBECONFIG_FOLDER}/generateArtifactsJob.yaml" 102 | kubectl create -f ${KUBECONFIG_FOLDER}/generateArtifactsJob.yaml 103 | 104 | JOBSTATUS=$(kubectl get jobs |grep utils|awk '{print $3}') 105 | while [ "${JOBSTATUS}" != "1" ]; do 106 | echo "Waiting for generateArtifacts job to complete" 107 | sleep 1; 108 | # UTILSLEFT=$(kubectl get pods | grep utils | awk '{print $2}') 109 | UTILSSTATUS=$(kubectl get pods | grep "utils" | awk '{print $3}') 110 | if [ "${UTILSSTATUS}" == "Error" ]; then 111 | echo "There is an error in utils job. Please check logs." 112 | exit 1 113 | fi 114 | # UTILSLEFT=$(kubectl get pods | grep utils | awk '{print $2}') 115 | JOBSTATUS=$(kubectl get jobs |grep utils|awk '{print $3}') 116 | done 117 | 118 | 119 | # Create services for all peers, ca, orderer 120 | echo -e "\nCreating Services for blockchain network" 121 | echo "Running: kubectl create -f ${KUBECONFIG_FOLDER}/blockchain-services.yaml" 122 | kubectl create -f ${KUBECONFIG_FOLDER}/blockchain-services.yaml 123 | 124 | 125 | # Create peers, ca, orderer using Kubernetes Deployments 126 | echo -e "\nCreating new Deployment to create four peers in network" 127 | echo "Running: kubectl create -f ${KUBECONFIG_FOLDER}/peersDeployment.yaml" 128 | kubectl create -f ${KUBECONFIG_FOLDER}/peersDeployment.yaml 129 | 130 | echo "Checking if all deployments are ready" 131 | 132 | NUMPENDING=$(kubectl get deployments | grep blockchain | awk '{print $5}' | grep 0 | wc -l | awk '{print $1}') 133 | while [ "${NUMPENDING}" != "0" ]; do 134 | echo "Waiting on pending deployments. Deployments pending = ${NUMPENDING}" 135 | NUMPENDING=$(kubectl get deployments | grep blockchain | awk '{print $5}' | grep 0 | wc -l | awk '{print $1}') 136 | sleep 1 137 | done 138 | 139 | echo "Waiting for 15 seconds for peers and orderer to settle" 140 | sleep 15 141 | 142 | 143 | # Generate channel artifacts using configtx.yaml and then create channel 144 | echo -e "\nCreating channel transaction artifact and a channel" 145 | echo "Running: kubectl create -f ${KUBECONFIG_FOLDER}/create_channel.yaml" 146 | kubectl create -f ${KUBECONFIG_FOLDER}/create_channel.yaml 147 | 148 | JOBSTATUS=$(kubectl get jobs |grep createchannel |awk '{print $3}') 149 | while [ "${JOBSTATUS}" != "1" ]; do 150 | echo "Waiting for createchannel job to be completed" 151 | sleep 1; 152 | if [ "$(kubectl get pods | grep createchannel | awk '{print $3}')" == "Error" ]; then 153 | echo "Create Channel Failed" 154 | exit 1 155 | fi 156 | JOBSTATUS=$(kubectl get jobs |grep createchannel |awk '{print $3}') 157 | done 158 | echo "Create Channel Completed Successfully" 159 | 160 | 161 | # Join all peers on a channel 162 | echo -e "\nCreating joinchannel job" 163 | echo "Running: kubectl create -f ${KUBECONFIG_FOLDER}/join_channel.yaml" 164 | kubectl create -f ${KUBECONFIG_FOLDER}/join_channel.yaml 165 | 166 | JOBSTATUS=$(kubectl get jobs |grep joinchannel |awk '{print $3}') 167 | while [ "${JOBSTATUS}" != "1" ]; do 168 | echo "Waiting for joinchannel job to be completed" 169 | sleep 1; 170 | if [ "$(kubectl get pods | grep joinchannel | awk '{print $3}')" == "Error" ]; then 171 | echo "Join Channel Failed" 172 | exit 1 173 | fi 174 | JOBSTATUS=$(kubectl get jobs |grep joinchannel |awk '{print $3}') 175 | done 176 | echo "Join Channel Completed Successfully" 177 | 178 | 179 | # Install chaincode on each peer 180 | echo -e "\nCreating installchaincode job" 181 | echo "Running: kubectl create -f ${KUBECONFIG_FOLDER}/chaincode_install.yaml" 182 | kubectl create -f ${KUBECONFIG_FOLDER}/chaincode_install.yaml 183 | 184 | JOBSTATUS=$(kubectl get jobs |grep chaincodeinstall |awk '{print $3}') 185 | while [ "${JOBSTATUS}" != "1" ]; do 186 | echo "Waiting for chaincodeinstall job to be completed" 187 | sleep 1; 188 | if [ "$(kubectl get pods | grep chaincodeinstall | awk '{print $3}')" == "Error" ]; then 189 | echo "Chaincode Install Failed" 190 | exit 1 191 | fi 192 | JOBSTATUS=$(kubectl get jobs |grep chaincodeinstall |awk '{print $3}') 193 | done 194 | echo "Chaincode Install Completed Successfully" 195 | 196 | 197 | # Instantiate chaincode on channel 198 | echo -e "\nCreating chaincodeinstantiate job" 199 | echo "Running: kubectl create -f ${KUBECONFIG_FOLDER}/chaincode_instantiate.yaml" 200 | kubectl create -f ${KUBECONFIG_FOLDER}/chaincode_instantiate.yaml 201 | 202 | JOBSTATUS=$(kubectl get jobs |grep chaincodeinstantiate |awk '{print $3}') 203 | while [ "${JOBSTATUS}" != "1" ]; do 204 | echo "Waiting for chaincodeinstantiate job to be completed" 205 | sleep 1; 206 | if [ "$(kubectl get pods | grep chaincodeinstantiate | awk '{print $3}')" == "Error" ]; then 207 | echo "Chaincode Instantiation Failed" 208 | exit 1 209 | fi 210 | JOBSTATUS=$(kubectl get jobs |grep chaincodeinstantiate |awk '{print $3}') 211 | done 212 | echo "Chaincode Instantiation Completed Successfully" 213 | 214 | sleep 15 215 | echo -e "\nNetwork Setup Completed !!" 216 | -------------------------------------------------------------------------------- /blockchain-network-on-kubernetes/setup_blockchainNetwork_v2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -d "${PWD}/configFiles" ]; then 4 | KUBECONFIG_FOLDER=${PWD}/configFiles 5 | else 6 | echo "Configuration files are not found." 7 | exit 8 | fi 9 | 10 | # Create Docker deployment 11 | if [ "$(cat configFiles/peersDeployment.yaml | grep -c tcp://docker:2375)" != "0" ]; then 12 | echo "peersDeployment.yaml file was configured to use Docker in a container." 13 | echo "Creating Docker deployment" 14 | 15 | kubectl create -f ${KUBECONFIG_FOLDER}/docker-volume.yaml 16 | kubectl create -f ${KUBECONFIG_FOLDER}/docker.yaml 17 | sleep 5 18 | 19 | dockerPodStatus=$(kubectl get pods --selector=name=docker --output=jsonpath={.items..phase}) 20 | 21 | while [ "${dockerPodStatus}" != "Running" ]; do 22 | echo "Wating for Docker container to run. Current status of Docker is ${dockerPodStatus}" 23 | sleep 5; 24 | if [ "${dockerPodStatus}" == "Error" ]; then 25 | echo "There is an error in the Docker pod. Please check logs." 26 | exit 1 27 | fi 28 | dockerPodStatus=$(kubectl get pods --selector=name=docker --output=jsonpath={.items..phase}) 29 | done 30 | fi 31 | 32 | # Creating Persistant Volume 33 | echo -e "\nCreating volume" 34 | if [ "$(kubectl get pvc | grep shared-pvc | awk '{print $2}')" != "Bound" ]; then 35 | echo "The Persistant Volume does not seem to exist or is not bound" 36 | echo "Creating Persistant Volume" 37 | 38 | if [ "$1" == "--paid" ]; then 39 | echo "You passed argument --paid. Make sure you have an IBM Cloud Kubernetes - Standard tier. Else, remove --paid option" 40 | echo "Running: kubectl create -f ${KUBECONFIG_FOLDER}/createVolume-paid.yaml" 41 | kubectl create -f ${KUBECONFIG_FOLDER}/createVolume-paid.yaml 42 | sleep 5 43 | else 44 | echo "Running: kubectl create -f ${KUBECONFIG_FOLDER}/createVolume.yaml" 45 | kubectl create -f ${KUBECONFIG_FOLDER}/createVolume.yaml 46 | sleep 5 47 | fi 48 | 49 | if [ "kubectl get pvc | grep shared-pvc | awk '{print $3}'" != "shared-pv" ]; then 50 | echo "Success creating Persistant Volume" 51 | else 52 | echo "Failed to create Persistant Volume" 53 | fi 54 | else 55 | echo "The Persistant Volume exists, not creating again" 56 | fi 57 | 58 | # Copy the required files(configtx.yaml, cruypto-config.yaml, sample chaincode etc.) into volume 59 | echo -e "\nCreating Copy artifacts job." 60 | echo "Running: kubectl create -f ${KUBECONFIG_FOLDER}/copyArtifactsJob.yaml" 61 | kubectl create -f ${KUBECONFIG_FOLDER}/copyArtifactsJob.yaml 62 | 63 | pod=$(kubectl get pods --selector=job-name=copyartifacts --output=jsonpath={.items..metadata.name}) 64 | 65 | podSTATUS=$(kubectl get pods --selector=job-name=copyartifacts --output=jsonpath={.items..phase}) 66 | 67 | while [ "${podSTATUS}" != "Running" ]; do 68 | echo "Wating for container of copy artifact pod to run. Current status of ${pod} is ${podSTATUS}" 69 | sleep 5; 70 | if [ "${podSTATUS}" == "Error" ]; then 71 | echo "There is an error in copyartifacts job. Please check logs." 72 | exit 1 73 | fi 74 | podSTATUS=$(kubectl get pods --selector=job-name=copyartifacts --output=jsonpath={.items..phase}) 75 | done 76 | 77 | echo -e "${pod} is now ${podSTATUS}" 78 | echo -e "\nStarting to copy artifacts in persistent volume." 79 | 80 | #fix for this script to work on icp and ICS 81 | kubectl cp ./artifacts $pod:/shared/ 82 | 83 | echo "Waiting for 10 more seconds for copying artifacts to avoid any network delay" 84 | sleep 10 85 | JOBSTATUS=$(kubectl get jobs |grep "copyartifacts" |awk '{print $2}') 86 | while [ "${JOBSTATUS}" != "1/1" ]; do 87 | echo "Waiting for copyartifacts job to complete" 88 | sleep 1; 89 | PODSTATUS=$(kubectl get pods | grep "copyartifacts" | awk '{print $3}') 90 | if [ "${PODSTATUS}" == "Error" ]; then 91 | echo "There is an error in copyartifacts job. Please check logs." 92 | exit 1 93 | fi 94 | JOBSTATUS=$(kubectl get jobs |grep "copyartifacts" |awk '{print $2}') 95 | done 96 | echo "Copy artifacts job completed" 97 | 98 | 99 | # Generate Network artifacts using configtx.yaml and crypto-config.yaml 100 | echo -e "\nGenerating the required artifacts for Blockchain network" 101 | echo "Running: kubectl create -f ${KUBECONFIG_FOLDER}/generateArtifactsJob.yaml" 102 | kubectl create -f ${KUBECONFIG_FOLDER}/generateArtifactsJob.yaml 103 | 104 | JOBSTATUS=$(kubectl get jobs |grep utils|awk '{print $2}') 105 | while [ "${JOBSTATUS}" != "1/1" ]; do 106 | echo "Waiting for generateArtifacts job to complete" 107 | sleep 1; 108 | # UTILSLEFT=$(kubectl get pods | grep utils | awk '{print $2}') 109 | UTILSSTATUS=$(kubectl get pods | grep "utils" | awk '{print $3}') 110 | if [ "${UTILSSTATUS}" == "Error" ]; then 111 | echo "There is an error in utils job. Please check logs." 112 | exit 1 113 | fi 114 | # UTILSLEFT=$(kubectl get pods | grep utils | awk '{print $2}') 115 | JOBSTATUS=$(kubectl get jobs |grep utils|awk '{print $2}') 116 | done 117 | 118 | 119 | # Create services for all peers, ca, orderer 120 | echo -e "\nCreating Services for blockchain network" 121 | echo "Running: kubectl create -f ${KUBECONFIG_FOLDER}/blockchain-services.yaml" 122 | kubectl create -f ${KUBECONFIG_FOLDER}/blockchain-services.yaml 123 | 124 | 125 | # Create peers, ca, orderer using Kubernetes Deployments 126 | echo -e "\nCreating new Deployment to create four peers in network" 127 | echo "Running: kubectl create -f ${KUBECONFIG_FOLDER}/peersDeployment.yaml" 128 | kubectl create -f ${KUBECONFIG_FOLDER}/peersDeployment.yaml 129 | 130 | echo "Checking if all deployments are ready" 131 | 132 | NUMPENDING=$(kubectl get deployments | grep blockchain | awk '{print $5}' | grep 0 | wc -l | awk '{print $1}') 133 | while [ "${NUMPENDING}" != "0" ]; do 134 | echo "Waiting on pending deployments. Deployments pending = ${NUMPENDING}" 135 | NUMPENDING=$(kubectl get deployments | grep blockchain | awk '{print $5}' | grep 0 | wc -l | awk '{print $1}') 136 | sleep 1 137 | done 138 | 139 | echo "Waiting for 15 seconds for peers and orderer to settle" 140 | sleep 15 141 | 142 | 143 | # Generate channel artifacts using configtx.yaml and then create channel 144 | echo -e "\nCreating channel transaction artifact and a channel" 145 | echo "Running: kubectl create -f ${KUBECONFIG_FOLDER}/create_channel.yaml" 146 | kubectl create -f ${KUBECONFIG_FOLDER}/create_channel.yaml 147 | 148 | JOBSTATUS=$(kubectl get jobs |grep createchannel |awk '{print $2}') 149 | while [ "${JOBSTATUS}" != "1/1" ]; do 150 | echo "Waiting for createchannel job to be completed" 151 | sleep 1; 152 | if [ "$(kubectl get pods | grep createchannel | awk '{print $3}')" == "Error" ]; then 153 | echo "Create Channel Failed" 154 | exit 1 155 | fi 156 | JOBSTATUS=$(kubectl get jobs |grep createchannel |awk '{print $2}') 157 | done 158 | echo "Create Channel Completed Successfully" 159 | 160 | 161 | # Join all peers on a channel 162 | echo -e "\nCreating joinchannel job" 163 | echo "Running: kubectl create -f ${KUBECONFIG_FOLDER}/join_channel.yaml" 164 | kubectl create -f ${KUBECONFIG_FOLDER}/join_channel.yaml 165 | 166 | JOBSTATUS=$(kubectl get jobs |grep joinchannel |awk '{print $2}') 167 | while [ "${JOBSTATUS}" != "1/1" ]; do 168 | echo "Waiting for joinchannel job to be completed" 169 | sleep 1; 170 | if [ "$(kubectl get pods | grep joinchannel | awk '{print $3}')" == "Error" ]; then 171 | echo "Join Channel Failed" 172 | exit 1 173 | fi 174 | JOBSTATUS=$(kubectl get jobs |grep joinchannel |awk '{print $2}') 175 | done 176 | echo "Join Channel Completed Successfully" 177 | 178 | 179 | # Install chaincode on each peer 180 | echo -e "\nCreating installchaincode job" 181 | echo "Running: kubectl create -f ${KUBECONFIG_FOLDER}/chaincode_install.yaml" 182 | kubectl create -f ${KUBECONFIG_FOLDER}/chaincode_install.yaml 183 | 184 | JOBSTATUS=$(kubectl get jobs |grep chaincodeinstall |awk '{print $2}') 185 | while [ "${JOBSTATUS}" != "1/1" ]; do 186 | echo "Waiting for chaincodeinstall job to be completed" 187 | sleep 1; 188 | if [ "$(kubectl get pods | grep chaincodeinstall | awk '{print $3}')" == "Error" ]; then 189 | echo "Chaincode Install Failed" 190 | exit 1 191 | fi 192 | JOBSTATUS=$(kubectl get jobs |grep chaincodeinstall |awk '{print $2}') 193 | done 194 | echo "Chaincode Install Completed Successfully" 195 | 196 | 197 | # Instantiate chaincode on channel 198 | echo -e "\nCreating chaincodeinstantiate job" 199 | echo "Running: kubectl create -f ${KUBECONFIG_FOLDER}/chaincode_instantiate.yaml" 200 | kubectl create -f ${KUBECONFIG_FOLDER}/chaincode_instantiate.yaml 201 | 202 | JOBSTATUS=$(kubectl get jobs |grep chaincodeinstantiate |awk '{print $2}') 203 | while [ "${JOBSTATUS}" != "1/1" ]; do 204 | echo "Waiting for chaincodeinstantiate job to be completed" 205 | sleep 1; 206 | if [ "$(kubectl get pods | grep chaincodeinstantiate | awk '{print $3}')" == "Error" ]; then 207 | echo "Chaincode Instantiation Failed" 208 | exit 1 209 | fi 210 | JOBSTATUS=$(kubectl get jobs |grep chaincodeinstantiate |awk '{print $2}') 211 | done 212 | echo "Chaincode Instantiation Completed Successfully" 213 | 214 | sleep 15 215 | echo -e "\nNetwork Setup Completed !!" 216 | -------------------------------------------------------------------------------- /fabric-java-sdk-app/WebContent/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Class-Path: 3 | 4 | -------------------------------------------------------------------------------- /fabric-java-sdk-app/manifest.yml: -------------------------------------------------------------------------------- 1 | applications: 2 | - name: ngo-collaboration-java-app 3 | random-route: true 4 | memory: 256M 5 | path: target/ngo-collaboration-java.war 6 | buildpack: liberty-for-java 7 | env: 8 | KUBERNETES_IP_ADDRESS: xxx.xxx.xx.xx 9 | -------------------------------------------------------------------------------- /fabric-java-sdk-app/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | net.wasdev.maven.parent 7 | java7-parent 8 | 1.4 9 | 10 | 11 | fabric-java-sdk-app 12 | fabric-java-sdk-app 13 | 1.0 14 | war 15 | 16 | 17 | 18 | 19 | org.apache.maven.plugins 20 | maven-war-plugin 21 | 22 | false 23 | WebContent 24 | ngo-collaboration-java 25 | 26 | 27 | 28 | net.wasdev.wlp.maven.plugins 29 | liberty-maven-plugin 30 | 1.2.1 31 | 32 | 33 | 34 | 35 | 36 | net.wasdev.wlp.maven.plugins 37 | liberty-maven-plugin 38 | 39 | src/main/wlp/server.xml 40 | 41 | ../../../../../${project.build.finalName} 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | org.hyperledger.fabric-sdk-java 51 | fabric-sdk-java 52 | 1.4.0 53 | 54 | 55 | 56 | javax.servlet 57 | javax.servlet-api 58 | 3.0.1 59 | provided 60 | 61 | 62 | 63 | org.json 64 | json 65 | 20180813 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /fabric-java-sdk-app/src/main/java/org/example/client/CAClient.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | * Copyright 2019 IBM Corporation 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | 14 | package org.example.client; 15 | 16 | import java.lang.reflect.InvocationTargetException; 17 | import java.net.MalformedURLException; 18 | import java.util.Properties; 19 | import java.util.logging.Level; 20 | import java.util.logging.Logger; 21 | 22 | import org.example.user.UserContext; 23 | import org.example.util.Util; 24 | import org.hyperledger.fabric.sdk.Enrollment; 25 | import org.hyperledger.fabric.sdk.exception.CryptoException; 26 | import org.hyperledger.fabric.sdk.exception.InvalidArgumentException; 27 | import org.hyperledger.fabric.sdk.security.CryptoSuite; 28 | import org.hyperledger.fabric.sdk.security.CryptoSuite.Factory; 29 | import org.hyperledger.fabric_ca.sdk.HFCAClient; 30 | import org.hyperledger.fabric_ca.sdk.RegistrationRequest; 31 | 32 | /** 33 | * 34 | * @author bkadambi 35 | * 36 | */ 37 | public class CAClient { 38 | String caUrl; 39 | Properties caProperties; 40 | HFCAClient instance; 41 | UserContext adminContext; 42 | 43 | public UserContext getAdminUserContext() { 44 | return this.adminContext; 45 | } 46 | 47 | public void setAdminUserContext(UserContext userContext) { 48 | this.adminContext = userContext; 49 | } 50 | 51 | public CAClient(String caUrl, Properties caProperties) 52 | throws MalformedURLException, IllegalAccessException, InstantiationException, ClassNotFoundException, 53 | CryptoException, InvalidArgumentException, NoSuchMethodException, InvocationTargetException { 54 | this.caUrl = caUrl; 55 | this.caProperties = caProperties; 56 | this.init(); 57 | } 58 | 59 | public void init() 60 | throws MalformedURLException, IllegalAccessException, InstantiationException, ClassNotFoundException, 61 | CryptoException, InvalidArgumentException, NoSuchMethodException, InvocationTargetException { 62 | CryptoSuite cryptoSuite = Factory.getCryptoSuite(); 63 | this.instance = HFCAClient.createNewInstance(this.caUrl, this.caProperties); 64 | this.instance.setCryptoSuite(cryptoSuite); 65 | } 66 | 67 | public HFCAClient getInstance() { 68 | return this.instance; 69 | } 70 | 71 | public UserContext enrollAdminUser(String username, String password) throws Exception { 72 | UserContext userContext = Util.readUserContext(this.adminContext.getAffiliation(), username); 73 | if (userContext != null) { 74 | Logger.getLogger(CAClient.class.getName()).log(Level.WARNING, 75 | "CA -" + this.caUrl + " admin is already enrolled."); 76 | return userContext; 77 | } else { 78 | Enrollment adminEnrollment = this.instance.enroll(username, password); 79 | this.adminContext.setEnrollment(adminEnrollment); 80 | Logger.getLogger(CAClient.class.getName()).log(Level.INFO, "CA -" + this.caUrl + " Enrolled Admin."); 81 | return this.adminContext; 82 | } 83 | } 84 | 85 | public String registerUser(String username, String organization) throws Exception { 86 | UserContext userContext = Util.readUserContext(this.adminContext.getAffiliation(), username); 87 | if (userContext != null) { 88 | Logger.getLogger(CAClient.class.getName()).log(Level.WARNING, 89 | "CA -" + this.caUrl + " User " + username + " is already registered."); 90 | return null; 91 | } else { 92 | RegistrationRequest rr = new RegistrationRequest(username, organization); 93 | String enrollmentSecret = this.instance.register(rr, this.adminContext); 94 | Logger.getLogger(CAClient.class.getName()).log(Level.INFO, 95 | "CA -" + this.caUrl + " Registered User - " + username); 96 | return enrollmentSecret; 97 | } 98 | } 99 | 100 | public UserContext enrollUser(UserContext user, String secret) throws Exception { 101 | UserContext userContext = Util.readUserContext(this.adminContext.getAffiliation(), user.getName()); 102 | if (userContext != null) { 103 | Logger.getLogger(CAClient.class.getName()).log(Level.WARNING, 104 | "CA -" + this.caUrl + " User " + user.getName() + " is already enrolled"); 105 | return userContext; 106 | } else { 107 | Enrollment enrollment = this.instance.enroll(user.getName(), secret); 108 | user.setEnrollment(enrollment); 109 | Util.writeUserContext(user); 110 | Logger.getLogger(CAClient.class.getName()).log(Level.INFO, 111 | "CA -" + this.caUrl + " Enrolled User - " + user.getName()); 112 | return user; 113 | } 114 | } 115 | } -------------------------------------------------------------------------------- /fabric-java-sdk-app/src/main/java/org/example/client/ChannelClient.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | * Copyright 2019 IBM Corporation 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | 14 | package org.example.client; 15 | 16 | import java.io.File; 17 | import java.io.IOException; 18 | import java.nio.charset.StandardCharsets; 19 | import java.util.Collection; 20 | import java.util.HashMap; 21 | import java.util.Iterator; 22 | import java.util.Map; 23 | import java.util.concurrent.CompletableFuture; 24 | import java.util.logging.Level; 25 | import java.util.logging.Logger; 26 | import org.hyperledger.fabric.sdk.ChaincodeEndorsementPolicy; 27 | import org.hyperledger.fabric.sdk.ChaincodeID; 28 | import org.hyperledger.fabric.sdk.Channel; 29 | import org.hyperledger.fabric.sdk.InstantiateProposalRequest; 30 | import org.hyperledger.fabric.sdk.Peer; 31 | import org.hyperledger.fabric.sdk.ProposalResponse; 32 | import org.hyperledger.fabric.sdk.QueryByChaincodeRequest; 33 | import org.hyperledger.fabric.sdk.TransactionInfo; 34 | import org.hyperledger.fabric.sdk.TransactionProposalRequest; 35 | import org.hyperledger.fabric.sdk.BlockEvent.TransactionEvent; 36 | import org.hyperledger.fabric.sdk.ChaincodeID.Builder; 37 | import org.hyperledger.fabric.sdk.TransactionRequest.Type; 38 | import org.hyperledger.fabric.sdk.exception.ChaincodeEndorsementPolicyParseException; 39 | import org.hyperledger.fabric.sdk.exception.InvalidArgumentException; 40 | import org.hyperledger.fabric.sdk.exception.ProposalException; 41 | 42 | /** 43 | * 44 | * @author bkadambi 45 | * 46 | */ 47 | public class ChannelClient { 48 | String name; 49 | Channel channel; 50 | FabricClient fabClient; 51 | 52 | public String getName() { 53 | return this.name; 54 | } 55 | 56 | public Channel getChannel() { 57 | return this.channel; 58 | } 59 | 60 | public FabricClient getFabClient() { 61 | return this.fabClient; 62 | } 63 | 64 | public ChannelClient(String name, Channel channel, FabricClient fabClient) { 65 | this.name = name; 66 | this.channel = channel; 67 | this.fabClient = fabClient; 68 | } 69 | 70 | public Collection queryByChainCode(String chaincodeName, String functionName, String[] args) 71 | throws InvalidArgumentException, ProposalException { 72 | Logger.getLogger(ChannelClient.class.getName()).log(Level.INFO, 73 | "Querying " + functionName + " on channel " + this.channel.getName()); 74 | QueryByChaincodeRequest request = this.fabClient.getInstance().newQueryProposalRequest(); 75 | ChaincodeID ccid = ChaincodeID.newBuilder().setName(chaincodeName).build(); 76 | request.setChaincodeID(ccid); 77 | request.setFcn(functionName); 78 | if (args != null) { 79 | request.setArgs(args); 80 | } 81 | 82 | Collection response = this.channel.queryByChaincode(request); 83 | return response; 84 | } 85 | 86 | public Collection sendTransactionProposal(TransactionProposalRequest request) 87 | throws ProposalException, InvalidArgumentException { 88 | Logger.getLogger(ChannelClient.class.getName()).log(Level.INFO, 89 | "Sending transaction proposal on channel " + this.channel.getName()); 90 | Collection response = this.channel.sendTransactionProposal(request, this.channel.getPeers()); 91 | Iterator var3 = response.iterator(); 92 | 93 | while (var3.hasNext()) { 94 | ProposalResponse pres = (ProposalResponse) var3.next(); 95 | String stringResponse = new String(pres.getChaincodeActionResponsePayload()); 96 | Logger.getLogger(ChannelClient.class.getName()).log(Level.INFO, 97 | "Transaction proposal on channel " + this.channel.getName() + " " + pres.getMessage() + " " 98 | + pres.getStatus() + " with transaction id:" + pres.getTransactionID()); 99 | Logger.getLogger(ChannelClient.class.getName()).log(Level.INFO, stringResponse); 100 | } 101 | 102 | CompletableFuture cf = this.channel.sendTransaction(response); 103 | Logger.getLogger(ChannelClient.class.getName()).log(Level.INFO, cf.toString()); 104 | return response; 105 | } 106 | 107 | public Collection instantiateChainCode(String chaincodeName, String version, String chaincodePath, 108 | String language, String functionName, String[] functionArgs, String policyPath) 109 | throws InvalidArgumentException, ProposalException, ChaincodeEndorsementPolicyParseException, IOException { 110 | Logger.getLogger(ChannelClient.class.getName()).log(Level.INFO, 111 | "Instantiate proposal request " + chaincodeName + " on channel " + this.channel.getName() 112 | + " with Fabric client " + this.fabClient.getInstance().getUserContext().getMspId() + " " 113 | + this.fabClient.getInstance().getUserContext().getName()); 114 | InstantiateProposalRequest instantiateProposalRequest = this.fabClient.getInstance() 115 | .newInstantiationProposalRequest(); 116 | instantiateProposalRequest.setProposalWaitTime(180000L); 117 | Builder chaincodeIDBuilder = ChaincodeID.newBuilder().setName(chaincodeName).setVersion(version) 118 | .setPath(chaincodePath); 119 | ChaincodeID ccid = chaincodeIDBuilder.build(); 120 | Logger.getLogger(ChannelClient.class.getName()).log(Level.INFO, 121 | "Instantiating Chaincode ID " + chaincodeName + " on channel " + this.channel.getName()); 122 | instantiateProposalRequest.setChaincodeID(ccid); 123 | if (language.equals(Type.GO_LANG.toString())) { 124 | instantiateProposalRequest.setChaincodeLanguage(Type.GO_LANG); 125 | } else { 126 | instantiateProposalRequest.setChaincodeLanguage(Type.JAVA); 127 | } 128 | 129 | instantiateProposalRequest.setFcn(functionName); 130 | instantiateProposalRequest.setArgs(functionArgs); 131 | Map tm = new HashMap(); 132 | tm.put("HyperLedgerFabric", "InstantiateProposalRequest:JavaSDK".getBytes(StandardCharsets.UTF_8)); 133 | tm.put("method", "InstantiateProposalRequest".getBytes(StandardCharsets.UTF_8)); 134 | instantiateProposalRequest.setTransientMap(tm); 135 | if (policyPath != null) { 136 | ChaincodeEndorsementPolicy chaincodeEndorsementPolicy = new ChaincodeEndorsementPolicy(); 137 | chaincodeEndorsementPolicy.fromYamlFile(new File(policyPath)); 138 | instantiateProposalRequest.setChaincodeEndorsementPolicy(chaincodeEndorsementPolicy); 139 | } 140 | 141 | Collection responses = this.channel.sendInstantiationProposal(instantiateProposalRequest); 142 | CompletableFuture cf = this.channel.sendTransaction(responses); 143 | Logger.getLogger(ChannelClient.class.getName()).log(Level.INFO, 144 | "Chaincode " + chaincodeName + " on channel " + this.channel.getName() + " instantiation " + cf); 145 | return responses; 146 | } 147 | 148 | public TransactionInfo queryByTransactionId(String txnId) throws ProposalException, InvalidArgumentException { 149 | Logger.getLogger(ChannelClient.class.getName()).log(Level.INFO, 150 | "Querying by trasaction id " + txnId + " on channel " + this.channel.getName()); 151 | Collection peers = this.channel.getPeers(); 152 | Iterator var3 = peers.iterator(); 153 | if (var3.hasNext()) { 154 | Peer peer = (Peer) var3.next(); 155 | TransactionInfo info = this.channel.queryTransactionByID(peer, txnId); 156 | return info; 157 | } else { 158 | return null; 159 | } 160 | } 161 | } -------------------------------------------------------------------------------- /fabric-java-sdk-app/src/main/java/org/example/client/FabricClient.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | * Copyright 2019 IBM Corporation 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | 14 | package org.example.client; 15 | 16 | import java.io.File; 17 | import java.io.IOException; 18 | import java.lang.reflect.InvocationTargetException; 19 | import java.util.Collection; 20 | import java.util.logging.Level; 21 | import java.util.logging.Logger; 22 | import org.hyperledger.fabric.sdk.ChaincodeID; 23 | import org.hyperledger.fabric.sdk.Channel; 24 | import org.hyperledger.fabric.sdk.HFClient; 25 | import org.hyperledger.fabric.sdk.InstallProposalRequest; 26 | import org.hyperledger.fabric.sdk.Peer; 27 | import org.hyperledger.fabric.sdk.ProposalResponse; 28 | import org.hyperledger.fabric.sdk.User; 29 | import org.hyperledger.fabric.sdk.ChaincodeID.Builder; 30 | import org.hyperledger.fabric.sdk.exception.CryptoException; 31 | import org.hyperledger.fabric.sdk.exception.InvalidArgumentException; 32 | import org.hyperledger.fabric.sdk.exception.ProposalException; 33 | import org.hyperledger.fabric.sdk.security.CryptoSuite; 34 | import org.hyperledger.fabric.sdk.security.CryptoSuite.Factory; 35 | 36 | /** 37 | * 38 | * @author bkadambi 39 | * 40 | */ 41 | public class FabricClient { 42 | private HFClient instance; 43 | 44 | public HFClient getInstance() { 45 | return this.instance; 46 | } 47 | 48 | public FabricClient(User context) throws CryptoException, InvalidArgumentException, IllegalAccessException, 49 | InstantiationException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException { 50 | CryptoSuite cryptoSuite = Factory.getCryptoSuite(); 51 | this.instance = HFClient.createNewInstance(); 52 | this.instance.setCryptoSuite(cryptoSuite); 53 | this.instance.setUserContext(context); 54 | } 55 | 56 | public ChannelClient createChannelClient(String name) throws InvalidArgumentException { 57 | Channel channel = this.instance.newChannel(name); 58 | ChannelClient client = new ChannelClient(name, channel, this); 59 | return client; 60 | } 61 | 62 | public Collection deployChainCode(String chainCodeName, String chaincodePath, String codepath, 63 | String language, String version, Collection peers) 64 | throws InvalidArgumentException, IOException, ProposalException { 65 | InstallProposalRequest request = this.instance.newInstallProposalRequest(); 66 | Builder chaincodeIDBuilder = ChaincodeID.newBuilder().setName(chainCodeName).setVersion(version) 67 | .setPath(chaincodePath); 68 | ChaincodeID chaincodeID = chaincodeIDBuilder.build(); 69 | Logger.getLogger(FabricClient.class.getName()).log(Level.INFO, 70 | "Deploying chaincode " + chainCodeName + " using Fabric client " 71 | + this.instance.getUserContext().getMspId() + " " + this.instance.getUserContext().getName()); 72 | request.setChaincodeID(chaincodeID); 73 | request.setUserContext(this.instance.getUserContext()); 74 | request.setChaincodeSourceLocation(new File(codepath)); 75 | request.setChaincodeVersion(version); 76 | Collection responses = this.instance.sendInstallProposal(request, peers); 77 | return responses; 78 | } 79 | } -------------------------------------------------------------------------------- /fabric-java-sdk-app/src/main/java/org/example/config/ConfigNetwork.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | * Copyright 2019 IBM Corporation 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | 14 | package org.example.config; 15 | 16 | /** 17 | * 18 | * @author bkadambi 19 | * 20 | */ 21 | public class ConfigNetwork { 22 | 23 | public static final String IP = System.getenv("KUBERNETES_IP_ADDRESS"); // IP address of the Hyperledger Fabric Network Deployment on Kubernetes 24 | 25 | public static final String ORG1_MSP = "Org1MSP"; 26 | 27 | public static final String ORG1 = "org1"; 28 | 29 | public static final String ORG2_MSP = "Org2MSP"; 30 | 31 | public static final String ORG2 = "org2"; 32 | 33 | public static final String ADMIN = "admin"; 34 | 35 | public static final String ADMIN_PASSWORD = "adminpw"; 36 | 37 | public static final String CA_ORG1_URL = "http://" + IP + ":30054"; 38 | 39 | public static final String CA_ORG2_URL = "http://" + IP + ":30064"; 40 | 41 | public static final String ORDERER_URL = "grpc://" + IP + ":31010"; 42 | 43 | public static final String ORDERER_NAME = "blockchain-orderer"; 44 | 45 | public static final String CHANNEL_NAME = "channel1"; 46 | 47 | public static final String ORG1_PEER_2 = "blockchain-org1peer2"; 48 | 49 | public static final String ORG1_PEER_2_URL = "grpc://"+ IP +":30210"; 50 | 51 | public static final String ORG1_PEER_1 = "blockchain-org1peer1"; 52 | 53 | public static final String ORG1_PEER_1_URL = "grpc://"+ IP + ":30110"; 54 | 55 | public static final String ORG2_PEER_2 = "blockchain-org2peer2"; 56 | 57 | public static final String ORG2_PEER_2_URL = "grpc://" + IP + ":30410"; 58 | 59 | public static final String ORG2_PEER_1 = "blockchain-org2peer1"; 60 | 61 | public static final String ORG2_PEER_1_URL = "grpc://" + IP + ":30310"; 62 | 63 | public static final String CHAINCODE_ROOT_DIR = "chaincode"; 64 | 65 | public static final String CHAINCODE_1_NAME = "ngo"; 66 | 67 | public static final String CHAINCODE_1_VERSION = "1.0"; 68 | 69 | } 70 | -------------------------------------------------------------------------------- /fabric-java-sdk-app/src/main/java/org/example/servlet/CreateNeedServlet.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | * Copyright 2019 IBM Corporation 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | 14 | package org.example.servlet; 15 | 16 | import static java.nio.charset.StandardCharsets.UTF_8; 17 | 18 | import java.io.IOException; 19 | import java.util.Collection; 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | import java.util.logging.Level; 23 | import java.util.logging.Logger; 24 | 25 | import javax.servlet.ServletException; 26 | import javax.servlet.annotation.WebServlet; 27 | import javax.servlet.http.HttpServlet; 28 | import javax.servlet.http.HttpServletRequest; 29 | import javax.servlet.http.HttpServletResponse; 30 | 31 | import org.example.client.CAClient; 32 | import org.example.client.ChannelClient; 33 | import org.example.client.FabricClient; 34 | import org.example.config.ConfigNetwork; 35 | import org.example.user.UserContext; 36 | import org.example.util.Util; 37 | import org.hyperledger.fabric.sdk.ChaincodeID; 38 | import org.hyperledger.fabric.sdk.ChaincodeResponse.Status; 39 | import org.hyperledger.fabric.sdk.Channel; 40 | import org.hyperledger.fabric.sdk.Orderer; 41 | import org.hyperledger.fabric.sdk.Peer; 42 | import org.hyperledger.fabric.sdk.ProposalResponse; 43 | import org.hyperledger.fabric.sdk.TransactionProposalRequest; 44 | import org.json.JSONObject; 45 | 46 | /** 47 | * Servlet implementation class CreateNeedServlet 48 | */ 49 | @WebServlet("/CreateNeedServlet") 50 | public class CreateNeedServlet extends HttpServlet { 51 | private static final long serialVersionUID = 1L; 52 | private static int need_id = 1; 53 | 54 | /** 55 | * @see HttpServlet#HttpServlet() 56 | */ 57 | public CreateNeedServlet() { 58 | super(); 59 | // TODO Auto-generated constructor stub 60 | } 61 | 62 | /** 63 | * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse 64 | * response) 65 | */ 66 | protected void doGet(HttpServletRequest request, HttpServletResponse response) 67 | throws ServletException, IOException { 68 | try { 69 | StringBuilder sb = new StringBuilder(); 70 | String s; 71 | while ((s = request.getReader().readLine()) != null) { 72 | sb.append(s); 73 | } 74 | Logger.getLogger(getServletName()).log(Level.INFO, "Received configuration - " + sb.toString()); 75 | JSONObject req = new JSONObject(sb.toString()); 76 | req.put("needId", "N" + need_id); 77 | need_id = need_id + 1; 78 | createNeed(req); 79 | } catch (Exception e) { 80 | e.printStackTrace(); 81 | } 82 | response.getWriter().append("Created Need with ID:" + "N" + (need_id - 1)); 83 | } 84 | 85 | /** 86 | * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse 87 | * response) 88 | */ 89 | protected void doPost(HttpServletRequest request, HttpServletResponse response) 90 | throws ServletException, IOException { 91 | // TODO Auto-generated method stub 92 | doGet(request, response); 93 | } 94 | 95 | private static String createNeed(JSONObject req) { 96 | try { 97 | 98 | String caUrl = ConfigNetwork.CA_ORG1_URL; 99 | CAClient caClient = new CAClient(caUrl, null); 100 | // Enroll Admin to Org1MSP 101 | UserContext adminUserContext = new UserContext(); 102 | adminUserContext.setName(ConfigNetwork.ADMIN); 103 | adminUserContext.setAffiliation(ConfigNetwork.ORG1); 104 | adminUserContext.setMspId(ConfigNetwork.ORG1_MSP); 105 | caClient.setAdminUserContext(adminUserContext); 106 | adminUserContext = caClient.enrollAdminUser(ConfigNetwork.ADMIN, ConfigNetwork.ADMIN_PASSWORD); 107 | 108 | // Register and enroll user 109 | String username = req.getString("uname"); 110 | UserContext uContext = new UserContext(); 111 | uContext.setName(username); 112 | uContext.setAffiliation(ConfigNetwork.ORG1); 113 | uContext.setMspId(ConfigNetwork.ORG1_MSP); 114 | String secret = caClient.registerUser(username, ConfigNetwork.ORG1); 115 | uContext = caClient.enrollUser(uContext, secret); 116 | 117 | FabricClient fabClient = new FabricClient(uContext); 118 | 119 | ChannelClient channelClient = fabClient.createChannelClient(ConfigNetwork.CHANNEL_NAME); 120 | Channel channel = channelClient.getChannel(); 121 | Peer peer = fabClient.getInstance().newPeer(ConfigNetwork.ORG1_PEER_1, ConfigNetwork.ORG1_PEER_1_URL); 122 | Orderer orderer = fabClient.getInstance().newOrderer(ConfigNetwork.ORDERER_NAME, ConfigNetwork.ORDERER_URL); 123 | channel.addPeer(peer); 124 | channel.addOrderer(orderer); 125 | channel.initialize(); 126 | 127 | TransactionProposalRequest request = fabClient.getInstance().newTransactionProposalRequest(); 128 | ChaincodeID ccid = ChaincodeID.newBuilder().setName(ConfigNetwork.CHAINCODE_1_NAME).build(); 129 | request.setChaincodeID(ccid); 130 | request.setFcn("createNeed"); 131 | String[] arguments = { req.getString("needId"), req.getString("ngo"), req.getString("start_date"), 132 | req.getString("item"), req.getString("qty"), req.getString("end_date") }; 133 | request.setArgs(arguments); 134 | request.setProposalWaitTime(1000); 135 | 136 | Map tm2 = new HashMap<>(); 137 | tm2.put("HyperLedgerFabric", "TransactionProposalRequest:JavaSDK".getBytes(UTF_8)); 138 | tm2.put("method", "TransactionProposalRequest".getBytes(UTF_8)); 139 | tm2.put("result", ":)".getBytes(UTF_8)); 140 | tm2.put("rc", (ConfigNetwork.CHANNEL_NAME + "").getBytes(UTF_8)); 141 | tm2.put(Util.EXPECTED_EVENT_NAME, Util.EXPECTED_EVENT_DATA); 142 | request.setTransientMap(tm2); 143 | Collection responses = channelClient.sendTransactionProposal(request); 144 | for (ProposalResponse res : responses) { 145 | Status status = res.getStatus(); 146 | Logger.getLogger(CreateNeedServlet.class.getName()).log(Level.INFO, 147 | "Invoked createNeed on " + ConfigNetwork.CHAINCODE_1_NAME + ". Status - " + status); 148 | } 149 | 150 | } catch (Exception e) { 151 | e.printStackTrace(); 152 | } 153 | 154 | return null; 155 | } 156 | 157 | // Test code 158 | public static void main(String args[]) { 159 | JSONObject req = new JSONObject(); 160 | req.put("uname", "usr1"); 161 | req.put("needId", "N1"); 162 | req.put("ngo", "ngo1"); 163 | req.put("item", "food"); 164 | req.put("qty", "1000"); 165 | req.put("start_date", "19-2-2019"); 166 | req.put("end_date", "25-2-2019"); 167 | createNeed(req); 168 | } 169 | 170 | } 171 | -------------------------------------------------------------------------------- /fabric-java-sdk-app/src/main/java/org/example/servlet/CreatePledgeServlet.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | * Copyright 2019 IBM Corporation 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | 14 | package org.example.servlet; 15 | 16 | import static java.nio.charset.StandardCharsets.UTF_8; 17 | 18 | import java.io.IOException; 19 | import java.util.Collection; 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | import java.util.logging.Level; 23 | import java.util.logging.Logger; 24 | 25 | import javax.servlet.ServletException; 26 | import javax.servlet.annotation.WebServlet; 27 | import javax.servlet.http.HttpServlet; 28 | import javax.servlet.http.HttpServletRequest; 29 | import javax.servlet.http.HttpServletResponse; 30 | 31 | import org.example.client.CAClient; 32 | import org.example.client.ChannelClient; 33 | import org.example.client.FabricClient; 34 | import org.example.config.ConfigNetwork; 35 | import org.example.user.UserContext; 36 | import org.example.util.Util; 37 | import org.hyperledger.fabric.sdk.ChaincodeID; 38 | import org.hyperledger.fabric.sdk.Channel; 39 | import org.hyperledger.fabric.sdk.Orderer; 40 | import org.hyperledger.fabric.sdk.Peer; 41 | import org.hyperledger.fabric.sdk.ProposalResponse; 42 | import org.hyperledger.fabric.sdk.TransactionProposalRequest; 43 | import org.hyperledger.fabric.sdk.ChaincodeResponse.Status; 44 | import org.json.JSONObject; 45 | 46 | /** 47 | * Servlet implementation class CreatePledgeServlet 48 | */ 49 | @WebServlet("/CreatePledgeServlet") 50 | public class CreatePledgeServlet extends HttpServlet { 51 | private static final long serialVersionUID = 1L; 52 | private static int pledge_id = 1; 53 | 54 | /** 55 | * @see HttpServlet#HttpServlet() 56 | */ 57 | public CreatePledgeServlet() { 58 | super(); 59 | // TODO Auto-generated constructor stub 60 | } 61 | 62 | /** 63 | * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) 64 | */ 65 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 66 | try { 67 | StringBuilder sb = new StringBuilder(); 68 | String s; 69 | while ((s = request.getReader().readLine()) != null) { 70 | sb.append(s); 71 | } 72 | Logger.getLogger(getServletName()).log(Level.INFO, "Received configuration - " + sb.toString()); 73 | JSONObject req = new JSONObject(sb.toString()); 74 | req.put("pledgeId", "P" + pledge_id); 75 | pledge_id = pledge_id + 1; 76 | createPledge(req); 77 | } catch (Exception e) { 78 | e.printStackTrace(); 79 | } 80 | response.getWriter().append("Created Pledge with ID:" + "P" + (pledge_id - 1)); 81 | } 82 | 83 | /** 84 | * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) 85 | */ 86 | protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 87 | // TODO Auto-generated method stub 88 | doGet(request, response); 89 | } 90 | 91 | private static String createPledge(JSONObject req) { 92 | try { 93 | String caUrl = ConfigNetwork.CA_ORG1_URL; 94 | CAClient caClient = new CAClient(caUrl, null); 95 | // Enroll Admin to Org1MSP 96 | UserContext adminUserContext = new UserContext(); 97 | adminUserContext.setName(ConfigNetwork.ADMIN); 98 | adminUserContext.setAffiliation(ConfigNetwork.ORG1); 99 | adminUserContext.setMspId(ConfigNetwork.ORG1_MSP); 100 | caClient.setAdminUserContext(adminUserContext); 101 | adminUserContext = caClient.enrollAdminUser(ConfigNetwork.ADMIN, ConfigNetwork.ADMIN_PASSWORD); 102 | 103 | // Register and enroll user 104 | String username = req.getString("uname"); 105 | System.out.println("Registering Username:"+username); 106 | UserContext uContext = new UserContext(); 107 | uContext.setName(username); 108 | uContext.setAffiliation(ConfigNetwork.ORG1); 109 | uContext.setMspId(ConfigNetwork.ORG1_MSP); 110 | String secret = caClient.registerUser(username, ConfigNetwork.ORG1); 111 | uContext = caClient.enrollUser(uContext, secret); 112 | 113 | FabricClient fabClient = new FabricClient(uContext); 114 | 115 | ChannelClient channelClient = fabClient.createChannelClient(ConfigNetwork.CHANNEL_NAME); 116 | Channel channel = channelClient.getChannel(); 117 | Peer peer = fabClient.getInstance().newPeer(ConfigNetwork.ORG1_PEER_1, ConfigNetwork.ORG1_PEER_1_URL); 118 | Orderer orderer = fabClient.getInstance().newOrderer(ConfigNetwork.ORDERER_NAME, ConfigNetwork.ORDERER_URL); 119 | channel.addPeer(peer); 120 | channel.addOrderer(orderer); 121 | channel.initialize(); 122 | 123 | TransactionProposalRequest request = fabClient.getInstance().newTransactionProposalRequest(); 124 | ChaincodeID ccid = ChaincodeID.newBuilder().setName(ConfigNetwork.CHAINCODE_1_NAME).build(); 125 | request.setChaincodeID(ccid); 126 | request.setFcn("createPledge"); 127 | String[] arguments = { req.getString("pledgeId"), req.getString("needId"), req.getString("qty"), 128 | req.getString("ngo"), req.getString("status") }; 129 | request.setArgs(arguments); 130 | request.setProposalWaitTime(1000); 131 | 132 | Map tm2 = new HashMap<>(); 133 | tm2.put("HyperLedgerFabric", "TransactionProposalRequest:JavaSDK".getBytes(UTF_8)); 134 | tm2.put("method", "TransactionProposalRequest".getBytes(UTF_8)); 135 | tm2.put("result", ":)".getBytes(UTF_8)); 136 | tm2.put("rc", (ConfigNetwork.CHANNEL_NAME + "").getBytes(UTF_8)); 137 | tm2.put(Util.EXPECTED_EVENT_NAME, Util.EXPECTED_EVENT_DATA); 138 | request.setTransientMap(tm2); 139 | Collection responses = channelClient.sendTransactionProposal(request); 140 | for (ProposalResponse res : responses) { 141 | Status status = res.getStatus(); 142 | Logger.getLogger(CreatePledgeServlet.class.getName()).log(Level.INFO, 143 | "Invoked createPledge on " + ConfigNetwork.CHAINCODE_1_NAME + ". Status - " + status); 144 | } 145 | 146 | } catch (Exception e) { 147 | e.printStackTrace(); 148 | } 149 | 150 | return null; 151 | } 152 | 153 | // Test code 154 | public static void main(String args[]) { 155 | JSONObject req = new JSONObject(); 156 | req.put("uname", "usr2"); 157 | req.put("needId", "N1"); 158 | req.put("pledgeId", "P1"); 159 | req.put("qty", "100"); 160 | req.put("ngo", "NGO2"); 161 | req.put("status", "Pledged"); 162 | createPledge(req); 163 | } 164 | 165 | 166 | } 167 | -------------------------------------------------------------------------------- /fabric-java-sdk-app/src/main/java/org/example/servlet/QueryAllActiveNeedsServlet.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | * Copyright 2019 IBM Corporation 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | 14 | package org.example.servlet; 15 | 16 | import java.io.IOException; 17 | import java.util.Collection; 18 | import java.util.logging.Level; 19 | import java.util.logging.Logger; 20 | 21 | import javax.servlet.ServletException; 22 | import javax.servlet.annotation.WebServlet; 23 | import javax.servlet.http.HttpServlet; 24 | import javax.servlet.http.HttpServletRequest; 25 | import javax.servlet.http.HttpServletResponse; 26 | 27 | import org.example.client.CAClient; 28 | import org.example.client.ChannelClient; 29 | import org.example.client.FabricClient; 30 | import org.example.config.ConfigNetwork; 31 | import org.example.user.UserContext; 32 | import org.example.util.Util; 33 | import org.hyperledger.fabric.sdk.Channel; 34 | 35 | import org.hyperledger.fabric.sdk.Orderer; 36 | import org.hyperledger.fabric.sdk.Peer; 37 | import org.hyperledger.fabric.sdk.ProposalResponse; 38 | import org.json.JSONObject; 39 | 40 | /** 41 | * Servlet implementation class QueryAllActiveNeedsServlet 42 | */ 43 | @WebServlet("/QueryAllActiveNeedsServlet") 44 | public class QueryAllActiveNeedsServlet extends HttpServlet { 45 | private static final long serialVersionUID = 1L; 46 | 47 | /** 48 | * @see HttpServlet#HttpServlet() 49 | */ 50 | public QueryAllActiveNeedsServlet() { 51 | super(); 52 | // TODO Auto-generated constructor stub 53 | } 54 | 55 | /** 56 | * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) 57 | */ 58 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 59 | try { 60 | StringBuilder sb = new StringBuilder(); 61 | String s; 62 | while ((s = request.getReader().readLine()) != null) { 63 | sb.append(s); 64 | } 65 | Logger.getLogger(getServletName()).log(Level.INFO, "Received configuration - " + sb.toString()); 66 | JSONObject req = new JSONObject(sb.toString()); 67 | String res = queryAllActiveNeeds(req); 68 | response.getWriter().append(res); 69 | } catch (Exception e) { 70 | e.printStackTrace(); 71 | } 72 | } 73 | 74 | /** 75 | * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) 76 | */ 77 | protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 78 | // TODO Auto-generated method stub 79 | doGet(request, response); 80 | } 81 | 82 | private static String queryAllActiveNeeds(JSONObject req) 83 | { 84 | String stringResponse = ""; 85 | try { 86 | String caUrl = ConfigNetwork.CA_ORG1_URL; 87 | CAClient caClient = new CAClient(caUrl, null); 88 | // Enroll Admin to Org1MSP 89 | UserContext adminUserContext = new UserContext(); 90 | adminUserContext.setName(org.example.config.ConfigNetwork.ADMIN); 91 | adminUserContext.setAffiliation(ConfigNetwork.ORG1); 92 | adminUserContext.setMspId(ConfigNetwork.ORG1_MSP); 93 | caClient.setAdminUserContext(adminUserContext); 94 | adminUserContext = caClient.enrollAdminUser(ConfigNetwork.ADMIN, ConfigNetwork.ADMIN_PASSWORD); 95 | 96 | // Register and enroll user 97 | String username = req.getString("uname"); 98 | UserContext uContext = new UserContext(); 99 | uContext.setName(username); 100 | uContext.setAffiliation(ConfigNetwork.ORG1); 101 | uContext.setMspId(ConfigNetwork.ORG1_MSP); 102 | String secret = caClient.registerUser(username, ConfigNetwork.ORG1); 103 | uContext = caClient.enrollUser(uContext, secret); 104 | 105 | FabricClient fabClient = new FabricClient(uContext); 106 | 107 | ChannelClient channelClient = fabClient.createChannelClient(ConfigNetwork.CHANNEL_NAME); 108 | Channel channel = channelClient.getChannel(); 109 | Peer peer = fabClient.getInstance().newPeer(ConfigNetwork.ORG1_PEER_1, ConfigNetwork.ORG1_PEER_1_URL); 110 | Orderer orderer = fabClient.getInstance().newOrderer(ConfigNetwork.ORDERER_NAME, ConfigNetwork.ORDERER_URL); 111 | channel.addPeer(peer); 112 | channel.addOrderer(orderer); 113 | channel.initialize(); 114 | 115 | Logger.getLogger(QueryAllActiveNeedsServlet.class.getName()).log(Level.INFO, "Querying for all active needs ..."); 116 | String[] args = {req.getString("date")}; 117 | Collection responsesQuery = channelClient.queryByChainCode(ConfigNetwork.CHAINCODE_1_NAME, "queryAllActiveNeeds", args); 118 | for (ProposalResponse pres : responsesQuery) { 119 | stringResponse = new String(pres.getChaincodeActionResponsePayload()); 120 | Logger.getLogger(QueryAllActiveNeedsServlet.class.getName()).log(Level.INFO, stringResponse); 121 | } 122 | 123 | } catch (Exception e) { 124 | e.printStackTrace(); 125 | } 126 | return stringResponse; 127 | } 128 | 129 | //Test code 130 | public static void main(String[] args) { 131 | JSONObject req = new JSONObject(); 132 | req.put("uname", "usr2"); 133 | req.put("date", "19-2-2019"); 134 | queryAllActiveNeeds(req); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /fabric-java-sdk-app/src/main/java/org/example/servlet/QueryAllNeedsServlet.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | * Copyright 2019 IBM Corporation 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | 14 | package org.example.servlet; 15 | 16 | import java.io.IOException; 17 | import java.util.Collection; 18 | import java.util.logging.Level; 19 | import java.util.logging.Logger; 20 | 21 | import javax.servlet.ServletException; 22 | import javax.servlet.annotation.WebServlet; 23 | import javax.servlet.http.HttpServlet; 24 | import javax.servlet.http.HttpServletRequest; 25 | import javax.servlet.http.HttpServletResponse; 26 | 27 | import org.example.client.CAClient; 28 | import org.example.client.ChannelClient; 29 | import org.example.client.FabricClient; 30 | import org.example.config.ConfigNetwork; 31 | import org.example.user.UserContext; 32 | import org.example.util.Util; 33 | import org.hyperledger.fabric.sdk.Channel; 34 | import org.hyperledger.fabric.sdk.Orderer; 35 | import org.hyperledger.fabric.sdk.Peer; 36 | import org.hyperledger.fabric.sdk.ProposalResponse; 37 | import org.json.JSONObject; 38 | 39 | /** 40 | * Servlet implementation class QueryAllNeedsServlet 41 | */ 42 | @WebServlet("/QueryAllNeedsServlet") 43 | public class QueryAllNeedsServlet extends HttpServlet { 44 | private static final long serialVersionUID = 1L; 45 | 46 | /** 47 | * @see HttpServlet#HttpServlet() 48 | */ 49 | public QueryAllNeedsServlet() { 50 | super(); 51 | // TODO Auto-generated constructor stub 52 | } 53 | 54 | /** 55 | * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse 56 | * response) 57 | */ 58 | protected void doGet(HttpServletRequest request, HttpServletResponse response) 59 | throws ServletException, IOException { 60 | try { 61 | StringBuilder sb = new StringBuilder(); 62 | String s; 63 | while ((s = request.getReader().readLine()) != null) { 64 | sb.append(s); 65 | } 66 | Logger.getLogger(getServletName()).log(Level.INFO, "Received configuration - " + sb.toString()); 67 | JSONObject req = new JSONObject(sb.toString()); 68 | String res = queryAllNeeds(req); 69 | response.getWriter().append(res); 70 | } catch (Exception e) { 71 | e.printStackTrace(); 72 | } 73 | } 74 | 75 | /** 76 | * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse 77 | * response) 78 | */ 79 | protected void doPost(HttpServletRequest request, HttpServletResponse response) 80 | throws ServletException, IOException { 81 | // TODO Auto-generated method stub 82 | doGet(request, response); 83 | } 84 | 85 | private static String queryAllNeeds(JSONObject req) { 86 | String stringResponse = ""; 87 | try { 88 | String caUrl = ConfigNetwork.CA_ORG1_URL; 89 | CAClient caClient = new CAClient(caUrl, null); 90 | // Enroll Admin to Org1MSP 91 | UserContext adminUserContext = new UserContext(); 92 | adminUserContext.setName(org.example.config.ConfigNetwork.ADMIN); 93 | adminUserContext.setAffiliation(ConfigNetwork.ORG1); 94 | adminUserContext.setMspId(ConfigNetwork.ORG1_MSP); 95 | caClient.setAdminUserContext(adminUserContext); 96 | adminUserContext = caClient.enrollAdminUser(ConfigNetwork.ADMIN, ConfigNetwork.ADMIN_PASSWORD); 97 | 98 | // Register and enroll user 99 | String username = req.getString("uname"); 100 | UserContext uContext = new UserContext(); 101 | uContext.setName(username); 102 | uContext.setAffiliation(ConfigNetwork.ORG1); 103 | uContext.setMspId(ConfigNetwork.ORG1_MSP); 104 | String secret = caClient.registerUser(username, ConfigNetwork.ORG1); 105 | uContext = caClient.enrollUser(uContext, secret); 106 | 107 | FabricClient fabClient = new FabricClient(uContext); 108 | 109 | ChannelClient channelClient = fabClient.createChannelClient(ConfigNetwork.CHANNEL_NAME); 110 | Channel channel = channelClient.getChannel(); 111 | Peer peer = fabClient.getInstance().newPeer(ConfigNetwork.ORG1_PEER_1, ConfigNetwork.ORG1_PEER_1_URL); 112 | Orderer orderer = fabClient.getInstance().newOrderer(ConfigNetwork.ORDERER_NAME, ConfigNetwork.ORDERER_URL); 113 | channel.addPeer(peer); 114 | channel.addOrderer(orderer); 115 | channel.initialize(); 116 | 117 | Logger.getLogger(QueryAllNeedsServlet.class.getName()).log(Level.INFO, "Querying for all needs ..."); 118 | Collection responsesQuery = channelClient.queryByChainCode(ConfigNetwork.CHAINCODE_1_NAME, 119 | "queryAllNeeds", null); 120 | for (ProposalResponse pres : responsesQuery) { 121 | stringResponse = new String(pres.getChaincodeActionResponsePayload()); 122 | Logger.getLogger(QueryAllNeedsServlet.class.getName()).log(Level.INFO, stringResponse); 123 | } 124 | 125 | } catch (Exception e) { 126 | e.printStackTrace(); 127 | } 128 | return stringResponse; 129 | } 130 | 131 | //Test code 132 | public static void main(String[] args) { 133 | JSONObject req = new JSONObject(); 134 | req.put("uname", "usr1"); 135 | queryAllNeeds(req); 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /fabric-java-sdk-app/src/main/java/org/example/servlet/QueryAllPastNeedsServlet.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | * Copyright 2019 IBM Corporation 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | 14 | package org.example.servlet; 15 | 16 | import java.io.IOException; 17 | import java.util.Collection; 18 | import java.util.logging.Level; 19 | import java.util.logging.Logger; 20 | 21 | import javax.servlet.ServletException; 22 | import javax.servlet.annotation.WebServlet; 23 | import javax.servlet.http.HttpServlet; 24 | import javax.servlet.http.HttpServletRequest; 25 | import javax.servlet.http.HttpServletResponse; 26 | 27 | import org.example.client.CAClient; 28 | import org.example.client.ChannelClient; 29 | import org.example.client.FabricClient; 30 | import org.example.config.ConfigNetwork; 31 | import org.example.user.UserContext; 32 | import org.example.util.Util; 33 | import org.hyperledger.fabric.sdk.Channel; 34 | import org.hyperledger.fabric.sdk.Orderer; 35 | import org.hyperledger.fabric.sdk.Peer; 36 | import org.hyperledger.fabric.sdk.ProposalResponse; 37 | import org.json.JSONObject; 38 | 39 | /** 40 | * Servlet implementation class QueryAllPastNeedsServlet 41 | */ 42 | @WebServlet("/QueryAllPastNeedsServlet") 43 | public class QueryAllPastNeedsServlet extends HttpServlet { 44 | private static final long serialVersionUID = 1L; 45 | 46 | /** 47 | * @see HttpServlet#HttpServlet() 48 | */ 49 | public QueryAllPastNeedsServlet() { 50 | super(); 51 | // TODO Auto-generated constructor stub 52 | } 53 | 54 | /** 55 | * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) 56 | */ 57 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 58 | try { 59 | StringBuilder sb = new StringBuilder(); 60 | String s; 61 | while ((s = request.getReader().readLine()) != null) { 62 | sb.append(s); 63 | } 64 | Logger.getLogger(getServletName()).log(Level.INFO, "Received configuration - " + sb.toString()); 65 | JSONObject req = new JSONObject(sb.toString()); 66 | String res = queryAllPastNeeds(req); 67 | response.getWriter().append(res); 68 | } catch (Exception e) { 69 | e.printStackTrace(); 70 | } 71 | } 72 | 73 | /** 74 | * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) 75 | */ 76 | protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 77 | // TODO Auto-generated method stub 78 | doGet(request, response); 79 | } 80 | 81 | private static String queryAllPastNeeds(JSONObject req) 82 | { 83 | String stringResponse = ""; 84 | try { 85 | String caUrl = ConfigNetwork.CA_ORG1_URL; 86 | CAClient caClient = new CAClient(caUrl, null); 87 | // Enroll Admin to Org1MSP 88 | UserContext adminUserContext = new UserContext(); 89 | adminUserContext.setName(org.example.config.ConfigNetwork.ADMIN); 90 | adminUserContext.setAffiliation(ConfigNetwork.ORG1); 91 | adminUserContext.setMspId(ConfigNetwork.ORG1_MSP); 92 | caClient.setAdminUserContext(adminUserContext); 93 | adminUserContext = caClient.enrollAdminUser(ConfigNetwork.ADMIN, ConfigNetwork.ADMIN_PASSWORD); 94 | 95 | // Register and enroll user 96 | String username = req.getString("uname"); 97 | UserContext uContext = new UserContext(); 98 | uContext.setName(username); 99 | uContext.setAffiliation(ConfigNetwork.ORG1); 100 | uContext.setMspId(ConfigNetwork.ORG1_MSP); 101 | String secret = caClient.registerUser(username, ConfigNetwork.ORG1); 102 | uContext = caClient.enrollUser(uContext, secret); 103 | 104 | FabricClient fabClient = new FabricClient(uContext); 105 | 106 | ChannelClient channelClient = fabClient.createChannelClient(ConfigNetwork.CHANNEL_NAME); 107 | Channel channel = channelClient.getChannel(); 108 | Peer peer = fabClient.getInstance().newPeer(ConfigNetwork.ORG1_PEER_1, ConfigNetwork.ORG1_PEER_1_URL); 109 | Orderer orderer = fabClient.getInstance().newOrderer(ConfigNetwork.ORDERER_NAME, ConfigNetwork.ORDERER_URL); 110 | channel.addPeer(peer); 111 | channel.addOrderer(orderer); 112 | channel.initialize(); 113 | 114 | Logger.getLogger(QueryAllPastNeedsServlet.class.getName()).log(Level.INFO, "Querying for all past needs ..."); 115 | String[] args = {req.getString("date")}; 116 | Collection responsesQuery = channelClient.queryByChainCode(ConfigNetwork.CHAINCODE_1_NAME, "queryAllPastNeeds", args); 117 | for (ProposalResponse pres : responsesQuery) { 118 | stringResponse = new String(pres.getChaincodeActionResponsePayload()); 119 | Logger.getLogger(QueryAllPastNeedsServlet.class.getName()).log(Level.INFO, stringResponse); 120 | } 121 | 122 | } catch (Exception e) { 123 | e.printStackTrace(); 124 | } 125 | return stringResponse; 126 | } 127 | 128 | //Test code 129 | public static void main(String[] args) { 130 | JSONObject req = new JSONObject(); 131 | req.put("uname", "usr1"); 132 | req.put("date", "26-2-2019"); 133 | queryAllPastNeeds(req); 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /fabric-java-sdk-app/src/main/java/org/example/servlet/QueryAllPledgesForNeedServlet.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | * Copyright 2019 IBM Corporation 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | 14 | package org.example.servlet; 15 | 16 | import java.io.IOException; 17 | import java.util.Collection; 18 | import java.util.logging.Level; 19 | import java.util.logging.Logger; 20 | 21 | import javax.servlet.ServletException; 22 | import javax.servlet.annotation.WebServlet; 23 | import javax.servlet.http.HttpServlet; 24 | import javax.servlet.http.HttpServletRequest; 25 | import javax.servlet.http.HttpServletResponse; 26 | 27 | import org.example.client.CAClient; 28 | import org.example.client.ChannelClient; 29 | import org.example.client.FabricClient; 30 | import org.example.config.ConfigNetwork; 31 | import org.example.user.UserContext; 32 | import org.example.util.Util; 33 | import org.hyperledger.fabric.sdk.Channel; 34 | import org.hyperledger.fabric.sdk.Orderer; 35 | import org.hyperledger.fabric.sdk.Peer; 36 | import org.hyperledger.fabric.sdk.ProposalResponse; 37 | import org.json.JSONObject; 38 | 39 | /** 40 | * Servlet implementation class QueryAllPledgesForNeedServlet 41 | */ 42 | @WebServlet("/QueryAllPledgesForNeedServlet") 43 | public class QueryAllPledgesForNeedServlet extends HttpServlet { 44 | private static final long serialVersionUID = 1L; 45 | 46 | /** 47 | * @see HttpServlet#HttpServlet() 48 | */ 49 | public QueryAllPledgesForNeedServlet() { 50 | super(); 51 | // TODO Auto-generated constructor stub 52 | } 53 | 54 | /** 55 | * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) 56 | */ 57 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 58 | try { 59 | StringBuilder sb = new StringBuilder(); 60 | String s; 61 | while ((s = request.getReader().readLine()) != null) { 62 | sb.append(s); 63 | } 64 | Logger.getLogger(getServletName()).log(Level.INFO, "Received configuration - " + sb.toString()); 65 | JSONObject req = new JSONObject(sb.toString()); 66 | String res = queryAllPledgesForNeed(req); 67 | response.getWriter().append(res); 68 | } catch (Exception e) { 69 | e.printStackTrace(); 70 | } 71 | } 72 | 73 | /** 74 | * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) 75 | */ 76 | protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 77 | // TODO Auto-generated method stub 78 | doGet(request, response); 79 | } 80 | 81 | private static String queryAllPledgesForNeed(JSONObject req) { 82 | String stringResponse = ""; 83 | try { 84 | String caUrl = ConfigNetwork.CA_ORG1_URL; 85 | CAClient caClient = new CAClient(caUrl, null); 86 | // Enroll Admin to Org1MSP 87 | UserContext adminUserContext = new UserContext(); 88 | adminUserContext.setName(org.example.config.ConfigNetwork.ADMIN); 89 | adminUserContext.setAffiliation(ConfigNetwork.ORG1); 90 | adminUserContext.setMspId(ConfigNetwork.ORG1_MSP); 91 | caClient.setAdminUserContext(adminUserContext); 92 | adminUserContext = caClient.enrollAdminUser(ConfigNetwork.ADMIN, ConfigNetwork.ADMIN_PASSWORD); 93 | 94 | // Register and enroll user 95 | String username = req.getString("uname"); 96 | UserContext uContext = new UserContext(); 97 | uContext.setName(username); 98 | uContext.setAffiliation(ConfigNetwork.ORG1); 99 | uContext.setMspId(ConfigNetwork.ORG1_MSP); 100 | String secret = caClient.registerUser(username, ConfigNetwork.ORG1); 101 | uContext = caClient.enrollUser(uContext, secret); 102 | 103 | FabricClient fabClient = new FabricClient(uContext); 104 | 105 | ChannelClient channelClient = fabClient.createChannelClient(ConfigNetwork.CHANNEL_NAME); 106 | Channel channel = channelClient.getChannel(); 107 | Peer peer = fabClient.getInstance().newPeer(ConfigNetwork.ORG1_PEER_1, ConfigNetwork.ORG1_PEER_1_URL); 108 | Orderer orderer = fabClient.getInstance().newOrderer(ConfigNetwork.ORDERER_NAME, ConfigNetwork.ORDERER_URL); 109 | channel.addPeer(peer); 110 | channel.addOrderer(orderer); 111 | channel.initialize(); 112 | 113 | Logger.getLogger(QueryAllPledgesForNeedServlet.class.getName()).log(Level.INFO, "Querying for pledges for a need ..."); 114 | String[] args = { req.getString("needId") }; 115 | Collection responsesQuery = channelClient.queryByChainCode(ConfigNetwork.CHAINCODE_1_NAME, 116 | "queryAllPledgesForNeed", args); 117 | for (ProposalResponse pres : responsesQuery) { 118 | stringResponse = new String(pres.getChaincodeActionResponsePayload()); 119 | Logger.getLogger(QueryAllPledgesForNeedServlet.class.getName()).log(Level.INFO, stringResponse); 120 | } 121 | 122 | } catch (Exception e) { 123 | e.printStackTrace(); 124 | } 125 | return stringResponse; 126 | } 127 | 128 | // Test code 129 | public static void main(String[] args) { 130 | JSONObject req = new JSONObject(); 131 | req.put("uname", "usr2"); 132 | req.put("needId", "N1"); 133 | queryAllPledgesForNeed(req); 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /fabric-java-sdk-app/src/main/java/org/example/servlet/QueryNeedServlet.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | * Copyright 2019 IBM Corporation 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | 14 | package org.example.servlet; 15 | 16 | import java.io.IOException; 17 | import java.util.Collection; 18 | import java.util.logging.Level; 19 | import java.util.logging.Logger; 20 | 21 | import javax.servlet.ServletException; 22 | import javax.servlet.annotation.WebServlet; 23 | import javax.servlet.http.HttpServlet; 24 | import javax.servlet.http.HttpServletRequest; 25 | import javax.servlet.http.HttpServletResponse; 26 | 27 | import org.example.client.CAClient; 28 | import org.example.client.ChannelClient; 29 | import org.example.client.FabricClient; 30 | import org.example.config.ConfigNetwork; 31 | import org.example.user.UserContext; 32 | import org.example.util.Util; 33 | import org.hyperledger.fabric.sdk.Channel; 34 | 35 | import org.hyperledger.fabric.sdk.Orderer; 36 | import org.hyperledger.fabric.sdk.Peer; 37 | import org.hyperledger.fabric.sdk.ProposalResponse; 38 | import org.json.JSONObject; 39 | 40 | /** 41 | * Servlet implementation class QueryAllActiveNeedsServlet 42 | */ 43 | @WebServlet("/QueryNeedServlet") 44 | public class QueryNeedServlet extends HttpServlet { 45 | private static final long serialVersionUID = 1L; 46 | 47 | /** 48 | * @see HttpServlet#HttpServlet() 49 | */ 50 | public QueryNeedServlet() { 51 | super(); 52 | // TODO Auto-generated constructor stub 53 | } 54 | 55 | /** 56 | * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse 57 | * response) 58 | */ 59 | protected void doGet(HttpServletRequest request, HttpServletResponse response) 60 | throws ServletException, IOException { 61 | try { 62 | StringBuilder sb = new StringBuilder(); 63 | String s; 64 | while ((s = request.getReader().readLine()) != null) { 65 | sb.append(s); 66 | } 67 | Logger.getLogger(getServletName()).log(Level.INFO, "Received configuration - " + sb.toString()); 68 | JSONObject req = new JSONObject(sb.toString()); 69 | String res = queryNeed(req); 70 | response.getWriter().append(res); 71 | } catch (Exception e) { 72 | e.printStackTrace(); 73 | } 74 | } 75 | 76 | /** 77 | * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse 78 | * response) 79 | */ 80 | protected void doPost(HttpServletRequest request, HttpServletResponse response) 81 | throws ServletException, IOException { 82 | // TODO Auto-generated method stub 83 | doGet(request, response); 84 | } 85 | 86 | private static String queryNeed(JSONObject req) { 87 | String stringResponse = ""; 88 | try { 89 | String caUrl = ConfigNetwork.CA_ORG1_URL; 90 | CAClient caClient = new CAClient(caUrl, null); 91 | // Enroll Admin to Org1MSP 92 | UserContext adminUserContext = new UserContext(); 93 | adminUserContext.setName(org.example.config.ConfigNetwork.ADMIN); 94 | adminUserContext.setAffiliation(ConfigNetwork.ORG1); 95 | adminUserContext.setMspId(ConfigNetwork.ORG1_MSP); 96 | caClient.setAdminUserContext(adminUserContext); 97 | adminUserContext = caClient.enrollAdminUser(ConfigNetwork.ADMIN, ConfigNetwork.ADMIN_PASSWORD); 98 | 99 | // Register and enroll user 100 | String username = req.getString("uname"); 101 | UserContext uContext = new UserContext(); 102 | uContext.setName(username); 103 | uContext.setAffiliation(ConfigNetwork.ORG1); 104 | uContext.setMspId(ConfigNetwork.ORG1_MSP); 105 | String secret = caClient.registerUser(username, ConfigNetwork.ORG1); 106 | uContext = caClient.enrollUser(uContext, secret); 107 | 108 | FabricClient fabClient = new FabricClient(uContext); 109 | 110 | ChannelClient channelClient = fabClient.createChannelClient(ConfigNetwork.CHANNEL_NAME); 111 | Channel channel = channelClient.getChannel(); 112 | Peer peer = fabClient.getInstance().newPeer(ConfigNetwork.ORG1_PEER_1, ConfigNetwork.ORG1_PEER_1_URL); 113 | Orderer orderer = fabClient.getInstance().newOrderer(ConfigNetwork.ORDERER_NAME, ConfigNetwork.ORDERER_URL); 114 | channel.addPeer(peer); 115 | channel.addOrderer(orderer); 116 | channel.initialize(); 117 | 118 | Logger.getLogger(QueryNeedServlet.class.getName()).log(Level.INFO, "Querying for need ..."); 119 | String[] args = { req.getString("needId") }; 120 | Collection responsesQuery = channelClient.queryByChainCode(ConfigNetwork.CHAINCODE_1_NAME, 121 | "queryNeed", args); 122 | for (ProposalResponse pres : responsesQuery) { 123 | stringResponse = new String(pres.getChaincodeActionResponsePayload()); 124 | Logger.getLogger(QueryNeedServlet.class.getName()).log(Level.INFO, stringResponse); 125 | } 126 | 127 | } catch (Exception e) { 128 | e.printStackTrace(); 129 | } 130 | return stringResponse; 131 | } 132 | 133 | //Test code 134 | public static void main(String[] args) { 135 | JSONObject req = new JSONObject(); 136 | req.put("uname", "usr1"); 137 | req.put("needId", "N1"); 138 | queryNeed(req); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /fabric-java-sdk-app/src/main/java/org/example/servlet/QueryPledgeServlet.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | * Copyright 2019 IBM Corporation 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | 14 | package org.example.servlet; 15 | 16 | import java.io.IOException; 17 | import java.util.Collection; 18 | import java.util.logging.Level; 19 | import java.util.logging.Logger; 20 | 21 | import javax.servlet.ServletException; 22 | import javax.servlet.annotation.WebServlet; 23 | import javax.servlet.http.HttpServlet; 24 | import javax.servlet.http.HttpServletRequest; 25 | import javax.servlet.http.HttpServletResponse; 26 | 27 | import org.example.client.CAClient; 28 | import org.example.client.ChannelClient; 29 | import org.example.client.FabricClient; 30 | import org.example.config.ConfigNetwork; 31 | import org.example.user.UserContext; 32 | import org.example.util.Util; 33 | import org.hyperledger.fabric.sdk.Channel; 34 | import org.hyperledger.fabric.sdk.Orderer; 35 | import org.hyperledger.fabric.sdk.Peer; 36 | import org.hyperledger.fabric.sdk.ProposalResponse; 37 | import org.json.JSONObject; 38 | 39 | /** 40 | * Servlet implementation class QueryPledgeServlet 41 | */ 42 | @WebServlet("/QueryPledgeServlet") 43 | public class QueryPledgeServlet extends HttpServlet { 44 | private static final long serialVersionUID = 1L; 45 | 46 | /** 47 | * @see HttpServlet#HttpServlet() 48 | */ 49 | public QueryPledgeServlet() { 50 | super(); 51 | // TODO Auto-generated constructor stub 52 | } 53 | 54 | /** 55 | * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse 56 | * response) 57 | */ 58 | protected void doGet(HttpServletRequest request, HttpServletResponse response) 59 | throws ServletException, IOException { 60 | try { 61 | StringBuilder sb = new StringBuilder(); 62 | String s; 63 | while ((s = request.getReader().readLine()) != null) { 64 | sb.append(s); 65 | } 66 | Logger.getLogger(getServletName()).log(Level.INFO, "Received configuration - " + sb.toString()); 67 | JSONObject req = new JSONObject(sb.toString()); 68 | String res =queryPledge(req); 69 | response.getWriter().append(res); 70 | } catch (Exception e) { 71 | e.printStackTrace(); 72 | } 73 | } 74 | 75 | /** 76 | * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse 77 | * response) 78 | */ 79 | protected void doPost(HttpServletRequest request, HttpServletResponse response) 80 | throws ServletException, IOException { 81 | // TODO Auto-generated method stub 82 | doGet(request, response); 83 | } 84 | 85 | private static String queryPledge(JSONObject req) { 86 | String stringResponse = ""; 87 | try { 88 | String caUrl = ConfigNetwork.CA_ORG1_URL; 89 | CAClient caClient = new CAClient(caUrl, null); 90 | // Enroll Admin to Org1MSP 91 | UserContext adminUserContext = new UserContext(); 92 | adminUserContext.setName(org.example.config.ConfigNetwork.ADMIN); 93 | adminUserContext.setAffiliation(ConfigNetwork.ORG1); 94 | adminUserContext.setMspId(ConfigNetwork.ORG1_MSP); 95 | caClient.setAdminUserContext(adminUserContext); 96 | adminUserContext = caClient.enrollAdminUser(ConfigNetwork.ADMIN, ConfigNetwork.ADMIN_PASSWORD); 97 | 98 | // Register and enroll user 99 | String username = req.getString("uname"); 100 | UserContext uContext = new UserContext(); 101 | uContext.setName(username); 102 | uContext.setAffiliation(ConfigNetwork.ORG1); 103 | uContext.setMspId(ConfigNetwork.ORG1_MSP); 104 | String secret = caClient.registerUser(username, ConfigNetwork.ORG1); 105 | uContext = caClient.enrollUser(uContext, secret); 106 | 107 | FabricClient fabClient = new FabricClient(uContext); 108 | 109 | ChannelClient channelClient = fabClient.createChannelClient(ConfigNetwork.CHANNEL_NAME); 110 | Channel channel = channelClient.getChannel(); 111 | Peer peer = fabClient.getInstance().newPeer(ConfigNetwork.ORG1_PEER_1, ConfigNetwork.ORG1_PEER_1_URL); 112 | Orderer orderer = fabClient.getInstance().newOrderer(ConfigNetwork.ORDERER_NAME, ConfigNetwork.ORDERER_URL); 113 | channel.addPeer(peer); 114 | channel.addOrderer(orderer); 115 | channel.initialize(); 116 | 117 | Logger.getLogger(QueryPledgeServlet.class.getName()).log(Level.INFO, "Querying for pledge ..."); 118 | String[] args = { req.getString("pledgeId") }; 119 | Collection responsesQuery = channelClient.queryByChainCode(ConfigNetwork.CHAINCODE_1_NAME, 120 | "queryPledge", args); 121 | for (ProposalResponse pres : responsesQuery) { 122 | stringResponse = new String(pres.getChaincodeActionResponsePayload()); 123 | Logger.getLogger(QueryPledgeServlet.class.getName()).log(Level.INFO, stringResponse); 124 | } 125 | 126 | } catch (Exception e) { 127 | e.printStackTrace(); 128 | } 129 | return stringResponse; 130 | } 131 | 132 | //Test code 133 | public static void main(String[] args) { 134 | JSONObject req = new JSONObject(); 135 | req.put("uname", "usr1"); 136 | req.put("pledgeId", "P1"); 137 | queryPledge(req); 138 | } 139 | 140 | } 141 | -------------------------------------------------------------------------------- /fabric-java-sdk-app/src/main/java/org/example/user/CAEnrollment.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | * Copyright 2019 IBM Corporation 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | 14 | package org.example.user; 15 | 16 | import java.io.Serializable; 17 | import java.security.PrivateKey; 18 | import org.hyperledger.fabric.sdk.Enrollment; 19 | 20 | public class CAEnrollment implements Enrollment, Serializable { 21 | private static final long serialVersionUID = 550416591376968096L; 22 | private PrivateKey key; 23 | private String cert; 24 | 25 | public CAEnrollment(PrivateKey pkey, String signedPem) { 26 | this.key = pkey; 27 | this.cert = signedPem; 28 | } 29 | 30 | public PrivateKey getKey() { 31 | return this.key; 32 | } 33 | 34 | public String getCert() { 35 | return this.cert; 36 | } 37 | } -------------------------------------------------------------------------------- /fabric-java-sdk-app/src/main/java/org/example/user/RegisterEnrollUser.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | * Copyright 2019 IBM Corporation 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | 14 | package org.example.user; 15 | 16 | import java.util.Properties; 17 | 18 | import org.example.client.CAClient; 19 | import org.example.config.ConfigNetwork; 20 | import org.example.util.Util; 21 | 22 | public class RegisterEnrollUser { 23 | public static void main(String[] args) { 24 | try { 25 | Util.cleanUp(); 26 | String caUrl = ConfigNetwork.CA_ORG1_URL; 27 | CAClient caClient = new CAClient(caUrl, (Properties) null); 28 | UserContext adminUserContext = new UserContext(); 29 | adminUserContext.setName("admin"); 30 | adminUserContext.setAffiliation("org1"); 31 | adminUserContext.setMspId("Org1MSP"); 32 | caClient.setAdminUserContext(adminUserContext); 33 | adminUserContext = caClient.enrollAdminUser("admin", "adminpw"); 34 | UserContext userContext = new UserContext(); 35 | String name = "user" + System.currentTimeMillis(); 36 | userContext.setName(name); 37 | userContext.setAffiliation("org1"); 38 | userContext.setMspId("Org1MSP"); 39 | String eSecret = caClient.registerUser(name, "org1"); 40 | caClient.enrollUser(userContext, eSecret); 41 | } catch (Exception var7) { 42 | var7.printStackTrace(); 43 | } 44 | 45 | } 46 | } -------------------------------------------------------------------------------- /fabric-java-sdk-app/src/main/java/org/example/user/UserContext.java: -------------------------------------------------------------------------------- 1 | /****************************************************** 2 | * Copyright 2019 IBM Corporation 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | 14 | package org.example.user; 15 | 16 | import java.io.Serializable; 17 | import java.util.Set; 18 | import org.hyperledger.fabric.sdk.Enrollment; 19 | import org.hyperledger.fabric.sdk.User; 20 | 21 | public class UserContext implements User, Serializable { 22 | private static final long serialVersionUID = 1L; 23 | protected String name; 24 | protected Set roles; 25 | protected String account; 26 | protected String affiliation; 27 | protected Enrollment enrollment; 28 | protected String mspId; 29 | 30 | public void setName(String name) { 31 | this.name = name; 32 | } 33 | 34 | public void setRoles(Set roles) { 35 | this.roles = roles; 36 | } 37 | 38 | public void setAccount(String account) { 39 | this.account = account; 40 | } 41 | 42 | public void setAffiliation(String affiliation) { 43 | this.affiliation = affiliation; 44 | } 45 | 46 | public void setEnrollment(Enrollment enrollment) { 47 | this.enrollment = enrollment; 48 | } 49 | 50 | public void setMspId(String mspId) { 51 | this.mspId = mspId; 52 | } 53 | 54 | public String getName() { 55 | return this.name; 56 | } 57 | 58 | public Set getRoles() { 59 | return this.roles; 60 | } 61 | 62 | public String getAccount() { 63 | return this.account; 64 | } 65 | 66 | public String getAffiliation() { 67 | return this.affiliation; 68 | } 69 | 70 | public Enrollment getEnrollment() { 71 | return this.enrollment; 72 | } 73 | 74 | public String getMspId() { 75 | return this.mspId; 76 | } 77 | } -------------------------------------------------------------------------------- /fabric-java-sdk-app/src/main/java/org/example/util/Util.java: -------------------------------------------------------------------------------- 1 | package org.example.util; 2 | 3 | import static java.nio.charset.StandardCharsets.UTF_8; 4 | 5 | import java.io.BufferedReader; 6 | import java.io.File; 7 | import java.io.FileInputStream; 8 | import java.io.FileOutputStream; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | import java.io.InputStreamReader; 12 | import java.io.ObjectInputStream; 13 | import java.io.ObjectOutputStream; 14 | import java.nio.file.Files; 15 | import java.nio.file.Paths; 16 | import java.security.KeyFactory; 17 | import java.security.NoSuchAlgorithmException; 18 | import java.security.PrivateKey; 19 | import java.security.spec.InvalidKeySpecException; 20 | import java.security.spec.PKCS8EncodedKeySpec; 21 | import java.util.logging.Level; 22 | import java.util.logging.Logger; 23 | import javax.xml.bind.DatatypeConverter; 24 | 25 | import org.example.user.CAEnrollment; 26 | import org.example.user.UserContext; 27 | import org.hyperledger.fabric.sdk.exception.CryptoException; 28 | 29 | public class Util { 30 | 31 | public static final byte[] EXPECTED_EVENT_DATA = "!".getBytes(UTF_8); 32 | public static final String EXPECTED_EVENT_NAME = "event"; 33 | 34 | public static void writeUserContext(UserContext userContext) throws Exception { 35 | String directoryPath = "users/" + userContext.getAffiliation(); 36 | String filePath = directoryPath + "/" + userContext.getName() + ".ser"; 37 | File directory = new File(directoryPath); 38 | if (!directory.exists()) { 39 | directory.mkdirs(); 40 | } 41 | 42 | FileOutputStream file = new FileOutputStream(filePath); 43 | ObjectOutputStream out = new ObjectOutputStream(file); 44 | out.writeObject(userContext); 45 | out.close(); 46 | file.close(); 47 | } 48 | 49 | public static UserContext readUserContext(String affiliation, String username) throws Exception { 50 | String filePath = "users/" + affiliation + "/" + username + ".ser"; 51 | File file = new File(filePath); 52 | if (file.exists()) { 53 | FileInputStream fileStream = new FileInputStream(filePath); 54 | ObjectInputStream in = new ObjectInputStream(fileStream); 55 | UserContext uContext = (UserContext) in.readObject(); 56 | in.close(); 57 | fileStream.close(); 58 | return uContext; 59 | } else { 60 | return null; 61 | } 62 | } 63 | 64 | public static CAEnrollment getEnrollment(String keyFolderPath, String keyFileName, String certFolderPath, 65 | String certFileName) 66 | throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, CryptoException { 67 | PrivateKey key = null; 68 | String certificate = null; 69 | InputStream isKey = null; 70 | BufferedReader brKey = null; 71 | 72 | try { 73 | isKey = new FileInputStream(keyFolderPath + File.separator + keyFileName); 74 | brKey = new BufferedReader(new InputStreamReader(isKey)); 75 | StringBuilder keyBuilder = new StringBuilder(); 76 | 77 | for (String line = brKey.readLine(); line != null; line = brKey.readLine()) { 78 | if (line.indexOf("PRIVATE") == -1) { 79 | keyBuilder.append(line); 80 | } 81 | } 82 | 83 | certificate = new String(Files.readAllBytes(Paths.get(certFolderPath, certFileName))); 84 | byte[] encoded = DatatypeConverter.parseBase64Binary(keyBuilder.toString()); 85 | PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded); 86 | KeyFactory kf = KeyFactory.getInstance("EC"); 87 | key = kf.generatePrivate(keySpec); 88 | } finally { 89 | isKey.close(); 90 | brKey.close(); 91 | } 92 | 93 | CAEnrollment var15 = new CAEnrollment(key, certificate); 94 | return var15; 95 | } 96 | 97 | public static void cleanUp() { 98 | String directoryPath = "users"; 99 | File directory = new File(directoryPath); 100 | deleteDirectory(directory); 101 | } 102 | 103 | public static boolean deleteDirectory(File dir) { 104 | if (dir.isDirectory()) { 105 | File[] children = dir.listFiles(); 106 | 107 | for (int i = 0; i < children.length; ++i) { 108 | boolean success = deleteDirectory(children[i]); 109 | if (!success) { 110 | return false; 111 | } 112 | } 113 | } 114 | 115 | Logger.getLogger(Util.class.getName()).log(Level.INFO, "Deleting - " + dir.getName()); 116 | return dir.delete(); 117 | } 118 | } -------------------------------------------------------------------------------- /images/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/ngo-collaboration-using-blockchain/6acde53082bdb6c2e8bd40e8d536edfefc379886/images/architecture.png -------------------------------------------------------------------------------- /images/webui-active-needs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/ngo-collaboration-using-blockchain/6acde53082bdb6c2e8bd40e8d536edfefc379886/images/webui-active-needs.png -------------------------------------------------------------------------------- /images/webui-create-need.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/ngo-collaboration-using-blockchain/6acde53082bdb6c2e8bd40e8d536edfefc379886/images/webui-create-need.png -------------------------------------------------------------------------------- /images/webui-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/ngo-collaboration-using-blockchain/6acde53082bdb6c2e8bd40e8d536edfefc379886/images/webui-login.png -------------------------------------------------------------------------------- /images/webui-past-needs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/ngo-collaboration-using-blockchain/6acde53082bdb6c2e8bd40e8d536edfefc379886/images/webui-past-needs.png -------------------------------------------------------------------------------- /images/webui-pledge-qty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/ngo-collaboration-using-blockchain/6acde53082bdb6c2e8bd40e8d536edfefc379886/images/webui-pledge-qty.png -------------------------------------------------------------------------------- /images/webui-pledge-updated-qty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/ngo-collaboration-using-blockchain/6acde53082bdb6c2e8bd40e8d536edfefc379886/images/webui-pledge-updated-qty.png -------------------------------------------------------------------------------- /images/webui-pledges-for-a-need.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/ngo-collaboration-using-blockchain/6acde53082bdb6c2e8bd40e8d536edfefc379886/images/webui-pledges-for-a-need.png -------------------------------------------------------------------------------- /images/webui-tasks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/ngo-collaboration-using-blockchain/6acde53082bdb6c2e8bd40e8d536edfefc379886/images/webui-tasks.png -------------------------------------------------------------------------------- /images/worker-nodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/ngo-collaboration-using-blockchain/6acde53082bdb6c2e8bd40e8d536edfefc379886/images/worker-nodes.png -------------------------------------------------------------------------------- /webapp/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* -------------------------------------------------------------------------------- /webapp/app.js: -------------------------------------------------------------------------------- 1 | var createError = require('http-errors'); 2 | var express = require('express'); 3 | var path = require('path'); 4 | var cookieParser = require('cookie-parser'); 5 | var logger = require('morgan'); 6 | 7 | var indexRouter = require('./routes/index'); 8 | var usersRouter = require('./routes/users'); 9 | var loginRouter = require('./routes/login'); 10 | var dashboardRouter = require('./routes/dashboard'); 11 | var createneedRouter = require('./routes/createneed'); 12 | var needdetailsRouter = require('./routes/needdetails'); 13 | var pastneedsRouter = require('./routes/pastneeds'); 14 | var menuRouter = require('./routes/menu'); 15 | 16 | var app = express(); 17 | 18 | // view engine setup 19 | app.set('views', path.join(__dirname, 'views')); 20 | app.set('view engine', 'ejs'); 21 | 22 | app.use(logger('dev')); 23 | app.use(express.json()); 24 | app.use(express.urlencoded({ extended: false })); 25 | app.use(cookieParser()); 26 | app.use(express.static(path.join(__dirname, 'public'))); 27 | 28 | //app.use('/', indexRouter); 29 | app.use('/', loginRouter); 30 | app.use('/dashboard', dashboardRouter); 31 | app.use('/users', usersRouter); 32 | app.use('/createneed', createneedRouter); 33 | app.use('/needdetails', needdetailsRouter); 34 | app.use('/pastneeds', pastneedsRouter); 35 | app.use('/menu', menuRouter); 36 | 37 | // catch 404 and forward to error handler 38 | app.use(function(req, res, next) { 39 | next(createError(404)); 40 | }); 41 | 42 | // error handler 43 | app.use(function(err, req, res, next) { 44 | // set locals, only providing error in development 45 | res.locals.message = err.message; 46 | res.locals.error = req.app.get('env') === 'development' ? err : {}; 47 | 48 | // render the error page 49 | res.status(err.status || 500); 50 | res.render('error'); 51 | }); 52 | 53 | module.exports = app; 54 | -------------------------------------------------------------------------------- /webapp/bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('ngo-collab:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '3000'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | } 91 | -------------------------------------------------------------------------------- /webapp/config.js: -------------------------------------------------------------------------------- 1 | var config = {}; 2 | 3 | config.rest_base_url = 'https://ngo-collaboration-java-app-wacky-genet.mybluemix.net'; 4 | 5 | module.exports = config; -------------------------------------------------------------------------------- /webapp/manifest.yml: -------------------------------------------------------------------------------- 1 | applications: 2 | - name: ngo-collaboration-webui 3 | command: npm start 4 | path: . 5 | memory: 256M 6 | instances: 1 7 | random-route: true 8 | -------------------------------------------------------------------------------- /webapp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngo-collab", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www" 7 | }, 8 | "dependencies": { 9 | "cookie-parser": "~1.4.3", 10 | "debug": "~2.6.9", 11 | "ejs": "~2.5.7", 12 | "express": "~4.16.0", 13 | "http-errors": "~1.6.2", 14 | "morgan": "~1.9.0", 15 | "request": "^2.88.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /webapp/public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | .body { 2 | height: 500px; 3 | width: 960px; 4 | margin-left: auto; 5 | margin-right: auto; 6 | /* background-color: LightCyan; */ 7 | } 8 | 9 | .header { 10 | margin-top: 10px; 11 | font-size: 22px; 12 | height: 40px; 13 | width: 960px; 14 | background-color: #1E90FF; 15 | color: white; 16 | padding-left: 5px; 17 | padding-top: 3px; 18 | text-align: center; 19 | } 20 | 21 | .form { 22 | padding-top: 100px; 23 | padding-left: 30%; 24 | padding-right: 30%; 25 | /* border:1px solid black; */ 26 | } 27 | 28 | .loginButton{ 29 | margin-left: 37%; 30 | font-size: 16px; 31 | padding: 5px 30px; 32 | border-radius: 4px; 33 | /* border:1px solid red; */ 34 | } 35 | 36 | .header2 { 37 | font-size: 20px; 38 | height: 40px; 39 | width: 960px; 40 | color: black; 41 | padding-left: 5px; 42 | text-align: center; 43 | text-decoration: underline; 44 | } 45 | 46 | .dashboardTable { 47 | float: left; 48 | margin-left: 2px; 49 | width: 100%; 50 | /* padding: 2px; */ 51 | /*display: none;*/ 52 | border: 1px solid black; 53 | /* table-layout: auto; */ 54 | } 55 | 56 | .dashboardTable thead tr{ 57 | height: 35px; 58 | background-color: #E0FFFF; 59 | } 60 | 61 | .dashboardTable tbody tr{ 62 | height: 30px; 63 | } 64 | 65 | .pledgeButton { 66 | background-color: #e7e7e7; 67 | border-radius: 8px; 68 | -webkit-transition-duration: 0.4s; /* Safari */ 69 | transition-duration: 0.4s; 70 | } 71 | 72 | .pledgeButton:hover { 73 | background-color: #1E90FF; 74 | color: white; 75 | } 76 | 77 | .menu{ 78 | /* border:1px solid black; */ 79 | text-align: center; 80 | } 81 | 82 | .menu input{ 83 | width: 180px; 84 | } 85 | 86 | .note{ 87 | color: black; 88 | font-size: small; 89 | font-style: italic; 90 | } 91 | 92 | .homePageButton { 93 | float: left; 94 | height: 40px; 95 | width: 100%; 96 | } 97 | 98 | .newNeedForm { 99 | padding-top: 20px; 100 | padding-left: 25%; 101 | /* padding-right: 30%; */ 102 | /* border:1px solid black; */ 103 | } 104 | 105 | .needTable tr{ 106 | height: 40px; 107 | /* border:1px solid black; */ 108 | } 109 | 110 | .needTable td{ 111 | padding-left: 15px; 112 | } 113 | 114 | .tabs { 115 | height: 550px; 116 | width: 960px; 117 | } 118 | 119 | .tabContainer { 120 | height: 440px; 121 | width: 100%; 122 | } 123 | 124 | .wrapper { 125 | height: 50%; 126 | width: 100%; 127 | /* border:1px solid black; */ 128 | } 129 | 130 | .wrapper1 { 131 | height: 50%; 132 | width: 100%; 133 | display: none; 134 | /* border:1px solid black; */ 135 | } 136 | 137 | .predictedNeedTable { 138 | height: 50%; 139 | width: 100%; 140 | display: none; 141 | /* border:1px solid black; */ 142 | } 143 | 144 | .buttonPanel { 145 | height: 6%; 146 | width: 100%; 147 | text-align: center; 148 | /* border:1px solid black; */ 149 | } 150 | 151 | .ngocollabcontainer { 152 | border: 1px solid green; 153 | height: 100%; 154 | width: 32%; 155 | /* margin: 10px; */ 156 | display: none; 157 | } 158 | 159 | .gobutton { 160 | background-color: #e7e7e7; 161 | color: black; 162 | width: 80px; 163 | height: 24px; 164 | } 165 | 166 | select { 167 | width: 200px; 168 | } 169 | 170 | img { 171 | max-width: 100%; 172 | max-height: 90%; 173 | display: block; 174 | } 175 | 176 | .selectedRow { 177 | background-color: lightskyblue; 178 | } 179 | 180 | .needContainer { 181 | height: 100%; 182 | width: 20%; 183 | float: left; 184 | /* padding: 2px; */ 185 | display: none; 186 | border: 1px solid green; 187 | } 188 | 189 | .pledgeStatus { 190 | height: 100%; 191 | width: 20%; 192 | float: left; 193 | padding: 10px; 194 | margin-left: 2px; 195 | display: none; 196 | border: 1px solid green; 197 | } 198 | 199 | th, td { 200 | text-align: center 201 | } 202 | 203 | .boldlabel { 204 | font-weight: bold; 205 | } -------------------------------------------------------------------------------- /webapp/routes/createneed.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var util = require('util'); 4 | var config = require("../config"); 5 | var Request = require("request"); 6 | 7 | 8 | /* GET home page. */ 9 | router.get('/', function (req, res, next) { 10 | 11 | var paramMap = makeParamMap(req.url); 12 | var paramLength = Object.keys(paramMap).length; 13 | 14 | if (paramLength > 1) { 15 | paramMap['start_date'] = getTodayDate(); 16 | paramMap['uname'] = paramMap.ngo; 17 | 18 | var url = config.rest_base_url + "/CreateNeedServlet"; 19 | console.log("Create Need payload = " + JSON.stringify(paramMap)); 20 | Request.post({ 21 | url: url, 22 | body: paramMap, 23 | json: true 24 | }, function (error, response, body) { 25 | if (error) { 26 | return console.dir(error); 27 | } 28 | res.render('createneed', { result: body }); 29 | }); 30 | 31 | }else{ 32 | res.render('createneed', { result: 'Create Need' }); 33 | } 34 | }); 35 | 36 | 37 | 38 | function makeParamMap(uri) { 39 | var paramMap = {}; 40 | uri = uri.substring(2); 41 | var params = uri.split('&'); 42 | console.log("params = " + params); 43 | console.log("params length = " + params.length); 44 | for (var i = 0; i < params.length; i++) { 45 | var pair = params[i].split('='); 46 | if (pair[0] === 'username') { 47 | paramMap['ngo'] = pair[1]; 48 | delete paramMap['username']; 49 | } else { 50 | paramMap[pair[0]] = pair[1]; 51 | } 52 | } 53 | return paramMap; 54 | } 55 | 56 | function getTodayDate() { 57 | var today = new Date(); 58 | var dd = today.getDate(); 59 | var mm = today.getMonth() + 1; //January is 0! 60 | var yyyy = today.getFullYear(); 61 | 62 | if (dd < 10) { 63 | dd = '0' + dd 64 | } 65 | 66 | if (mm < 10) { 67 | mm = '0' + mm 68 | } 69 | 70 | today = dd + '-' + mm + '-' + yyyy; 71 | return today; 72 | 73 | } 74 | 75 | module.exports = router; -------------------------------------------------------------------------------- /webapp/routes/dashboard.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var Request = require("request"); 4 | var config = require("../config"); 5 | 6 | 7 | /* GET dashboard page. */ 8 | router.get('/', function (req, res, next) { 9 | 10 | var paramMap = makeParamMap(req.url); 11 | var paramLength = Object.keys(paramMap).length; 12 | var uname = req.url.substring(2).split('=')[1]; 13 | var pledgeStatus = null; 14 | 15 | 16 | var data = []; 17 | var todatDate = getTodayDate(); 18 | var url = config.rest_base_url + "/QueryAllActiveNeedsServlet"; 19 | var payload = { "uname": uname, "date": todatDate}; 20 | 21 | Request.post({ 22 | url: url, 23 | body: payload, 24 | json: true 25 | }, function (error, response, body) { 26 | if (error) { 27 | return console.dir(error); 28 | } 29 | console.log("Body = " + JSON.stringify(body)); 30 | 31 | if (!body) { // If there are no active needs available 32 | console.log("Body undefined"); 33 | res.render('dashboard', { isData: false, pledgeStatus: '' }); 34 | } else { // If there are active needs available 35 | body.forEach(element => { 36 | // TODO remove the hardcoded block below 37 | data.push(element); 38 | // if( element.Record.expected_fulfilment_date != '01-06-1979'){ 39 | // } 40 | }); 41 | 42 | if (paramLength > 1) { // it is a create pledge 43 | url = config.rest_base_url + "/CreatePledgeServlet"; 44 | var payload = { "uname": paramMap.ngo, "needId": paramMap.needId, "qty": paramMap.qty, "ngo": paramMap.ngo, "status": "Pledged" }; 45 | 46 | Request.post({ 47 | url: url, 48 | body: payload, 49 | json: true 50 | }, function (error, response, body) { 51 | if (error) { 52 | return console.dir(error); 53 | } 54 | res.render('dashboard', { needs: data, pledgeStatus: body, isData: true }); 55 | }); 56 | } else { 57 | res.render('dashboard', { needs: body, pledgeStatus: '', isData: true }); 58 | } 59 | } 60 | 61 | }); 62 | 63 | }); 64 | 65 | 66 | function postPledge(params) { 67 | 68 | var url = config.rest_base_url + "/CreatePledgeServlet"; 69 | var payload = { "uname": params.ngo, "needId": params.needId, "qty": params.qty, "ngo": params.ngo, "status": "Pledged" }; 70 | 71 | Request.post({ 72 | url: url, 73 | body: payload, 74 | json: true 75 | }, function (error, response, body) { 76 | if (error) { 77 | return console.dir(error); 78 | } 79 | return body; 80 | }); 81 | } 82 | 83 | function makeParamMap(uri) { 84 | var paramMap = {}; 85 | uri = uri.substring(2); 86 | var params = uri.split('&'); 87 | for (var i = 0; i < params.length; i++) { 88 | var pair = params[i].split('='); 89 | if (pair[0] === 'username') { 90 | paramMap['uname'] = pair[1]; 91 | delete paramMap['username']; 92 | } else { 93 | paramMap[pair[0]] = pair[1]; 94 | } 95 | } 96 | console.log("params = " + params); 97 | console.log("params length = " + params.length); 98 | return paramMap; 99 | } 100 | 101 | 102 | function getTodayDate() { 103 | var today = new Date(); 104 | var dd = today.getDate(); 105 | var mm = today.getMonth() + 1; //January is 0! 106 | var yyyy = today.getFullYear(); 107 | 108 | if (dd < 10) { 109 | dd = '0' + dd 110 | } 111 | 112 | if (mm < 10) { 113 | mm = '0' + mm 114 | } 115 | 116 | today = dd + '-' + mm + '-' + yyyy; 117 | return today; 118 | 119 | } 120 | 121 | module.exports = router; 122 | -------------------------------------------------------------------------------- /webapp/routes/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | /* GET home page. */ 5 | router.get('/', function(req, res, next) { 6 | res.render('index', { title: 'Express' }); 7 | }); 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /webapp/routes/login.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | /* GET home page. */ 5 | router.get('/', function(req, res, next) { 6 | res.render('login', { title: 'Login' }); 7 | }); 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /webapp/routes/menu.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | /* GET home page. */ 5 | router.get('/', function(req, res, next) { 6 | res.render('menu', { title: 'Menu' }); 7 | }); 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /webapp/routes/needdetails.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var Request = require("request"); 4 | var config = require("../config"); 5 | 6 | 7 | /* GET home page. */ 8 | router.get('/', function (req, res, next) { 9 | 10 | var paramMap = makeParamMap(req.url); 11 | var paramLength = Object.keys(paramMap).length; 12 | var uname = req.url.substring(2).split('=')[1]; 13 | 14 | var url = config.rest_base_url + "/QueryAllPledgesForNeedServlet"; 15 | var payload = { "uname": uname, "needId": paramMap["needid"] }; 16 | console.log("payload = " + payload); 17 | 18 | Request.post({ 19 | url: url, 20 | body: payload, 21 | json: true 22 | }, function (error, response, body) { 23 | if (error) { 24 | return console.dir(error); 25 | } 26 | res.render('needdetails', { pledgesdata: body}); 27 | }); 28 | }); 29 | 30 | function makeParamMap(uri) { 31 | var paramMap = {}; 32 | uri = uri.substring(2); 33 | var params = uri.split('&'); 34 | for (var i = 0; i < params.length; i++) { 35 | var pair = params[i].split('='); 36 | if (pair[0] === 'username') { 37 | paramMap['uname'] = pair[1]; 38 | delete paramMap['username']; 39 | } else { 40 | paramMap[pair[0]] = pair[1]; 41 | } 42 | } 43 | console.log("params = " + params); 44 | console.log("params length = " + params.length); 45 | return paramMap; 46 | } 47 | 48 | module.exports = router; -------------------------------------------------------------------------------- /webapp/routes/pastneeds.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var Request = require("request"); 4 | var config = require("../config"); 5 | 6 | /* GET dashboard page. */ 7 | router.get('/', function (req, res, next) { 8 | var uname = req.url.substring(2).split('=')[1]; 9 | var data={}; 10 | var url = config.rest_base_url + "/QueryAllPastNeedsServlet"; 11 | var body = { "uname": uname, "date": getTodayDate() }; 12 | 13 | Request.post({ 14 | url: url, 15 | body: body, 16 | json: true 17 | }, function (error, response, body) { 18 | if (error) { 19 | return console.dir(error); 20 | } 21 | res.render('pastneeds', { needs: body }); 22 | }); 23 | }); 24 | 25 | function getTodayDate() { 26 | var today = new Date(); 27 | var dd = today.getDate(); 28 | var mm = today.getMonth() + 1; //January is 0! 29 | var yyyy = today.getFullYear(); 30 | 31 | if (dd < 10) { 32 | dd = '0' + dd 33 | } 34 | 35 | if (mm < 10) { 36 | mm = '0' + mm 37 | } 38 | 39 | today = dd + '-' + mm + '-' + yyyy; 40 | return today; 41 | } 42 | 43 | module.exports = router; 44 | -------------------------------------------------------------------------------- /webapp/routes/users.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | /* GET users listing. */ 5 | router.get('/', function(req, res, next) { 6 | res.send('respond with a resource'); 7 | }); 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /webapp/views/createneed.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | NGO Collaboration Platform 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | 40 | 41 | 42 | 45 |
46 | 47 |
48 | Create a New Need 49 |
50 |

51 |
52 |
53 | 54 | 55 | 58 | 67 | 68 | 69 | 72 | 75 | 76 | 77 | 80 | 83 | 84 |
56 | Category 57 | 59 | 66 |
70 | Required Quantity 71 | 73 | 74 |
78 | Expected date of fulfillment 79 | 81 | 82 |
85 |

86 | 87 | 88 | 91 | 94 | 95 |
89 | 90 | 92 | 93 |
96 |
97 |
98 | 99 |
100 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /webapp/views/dashboard.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | NGO Collaboration Platform 5 | 6 | 7 | 9 | 10 | 53 | 54 | 55 | 56 | 57 | 60 |
61 | 62 |
63 | Active Needs 64 |
65 |

66 |
67 | <% if( isData ){ %> 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | <% for (var i=0; i 83 | 84 | 87 | 90 | 93 | 96 | 99 | 102 | 105 | 108 | 109 | <% } %> 110 | 111 |
Need IDCreated ByCreated OnCategoryQuanity RequiredPledged QtyExpected Date of FullfillmentPledge
85 | <%= needs[i].need_id %> 86 | 88 | <%= needs[i].created_by %> 89 | 91 | <%= needs[i].created_date %> 92 | 94 | <%= needs[i].need_category %> 95 | 97 | <%= needs[i].quantity %> 98 | 100 | <%= needs[i].pledged %> 101 | 103 | <%= needs[i].expected_fulfilment_date %> 104 | 106 | /> 107 |
112 |
113 | **Click on a row to get more details for a need. 114 |
115 | <% } 116 | else{ 117 | %> 118 | No active needs available 119 | <% 120 | } 121 | %> 122 |
123 |
124 | 125 |
126 | 127 |
128 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /webapp/views/error.ejs: -------------------------------------------------------------------------------- 1 |

<%= message %>

2 |

<%= error.status %>

3 |
<%= error.stack %>
4 | -------------------------------------------------------------------------------- /webapp/views/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= title %> 5 | 6 | 7 | 8 |

<%= title %>

9 |

Welcome to <%= title %>

10 | 11 | 12 | -------------------------------------------------------------------------------- /webapp/views/login.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | NGO Collaboration Platform 5 | 6 | 7 | 9 | 10 | 11 | 12 | 36 | 37 | 38 | 41 |
42 |
43 |
44 |
45 | 46 |
47 |
48 | 49 |
50 | 51 |
52 |
53 | 54 | 55 | -------------------------------------------------------------------------------- /webapp/views/menu.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | NGO Collaboration Platform 5 | 6 | 7 | 9 | 10 | 11 | 12 | 29 | 30 | 31 | 34 |

35 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /webapp/views/needdetails.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | NGO Collaboration Platform 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | 51 | 52 | 53 | 54 | 57 | 58 |
59 |
60 | Need Details 61 |
62 |

63 | 64 |
65 |
66 | <% 67 | if( pledgesdata && pledgesdata.length > 0 ){ 68 | %> 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | <% for (var i=0; i 79 | 80 | 83 | 86 | 89 | 90 | <% } %> 91 | 92 |
Pledge IDQuantityPledged By
81 | <%= pledgesdata[i].pledge_id %> 82 | 84 | <%= pledgesdata[i].pledged_quantity %> 85 | 87 | <%= pledgesdata[i].pledged_by %> 88 |
93 | <% 94 | } else{ 95 | %> 96 | No pledges are for this need 97 | <% 98 | } 99 | %> 100 |
101 |
102 |
103 | 104 |
105 | 106 |
107 | 108 | 109 | -------------------------------------------------------------------------------- /webapp/views/pastneeds.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | NGO Collaboration Platform 5 | 6 | 7 | 9 | 10 | 11 | 32 | 33 | 34 | 35 | 36 | 39 |
40 | 41 |
42 | Past Needs 43 |
44 |

45 | <% if( needs && needs.length > 0 ) { %> 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | <% for (var i=0; i 60 | 61 | 64 | 67 | 70 | 73 | 76 | 79 | 82 | 83 | <% } %> 84 | 85 |
Need IDCreated ByCreated OnCategoryQuanity RequiredPledgedExpected Date of Fullfillment
62 | <%= needs[i].need_id %> 63 | 65 | <%= needs[i].created_by %> 66 | 68 | <%= needs[i].created_date %> 69 | 71 | <%= needs[i].need_category %> 72 | 74 | <%= needs[i].quantity %> 75 | 77 | <%= needs[i].pledged %> 78 | 80 | <%= needs[i].expected_fulfilment_date %> 81 |
86 | <% } 87 | else{ 88 | %> 89 |

No past needs found

90 | <% 91 | } 92 | %> 93 |
94 |
95 |
96 | 97 |
98 | 99 |
100 | 101 | 102 | 103 | --------------------------------------------------------------------------------