Skip to content

Commit bf054cb

Browse files
mbwhitejt-nti
authored andcommitted
Add a brief example for the -as-a-service
Signed-off-by: Matthew B White <[email protected]>
1 parent f9ada8f commit bf054cb

File tree

10 files changed

+95
-65
lines changed

10 files changed

+95
-65
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Copyright 2019 IBM All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
# Example multi-stage dockerfile for Java Chaincode
5+
6+
# the first stage
7+
FROM gradle:jdk11 AS GRADLE_BUILD
8+
9+
# copy the build.gradle and src code to the container
10+
COPY src/ src/
11+
COPY build.gradle ./
12+
13+
# Build and package our code
14+
RUN gradle build shadowJar
15+
16+
17+
# the second stage of our build just needs the compiled files
18+
FROM openjdk:11-jre-slim
19+
# copy only the artifacts we need from the first stage and discard the rest
20+
COPY --from=GRADLE_BUILD /home/gradle/build/libs/chaincode.jar /chaincode.jar
21+
22+
ENV PORT 9999
23+
EXPOSE 9999
24+
25+
# set the startup command to execute the jar
26+
CMD ["java", "-jar", "/chaincode.jar"]
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Java Chaincode -as-a-service
2+
3+
This example shows how to start the chaincode in it's 'as-a-service' mode.
4+
Note that this has been improved over the original mechanism
5+
6+
## Build Changes
7+
8+
There are no changes required to tbe build file. For example the `build.gradle` can be left like this
9+
10+
```
11+
manifest {
12+
attributes 'Main-Class': 'org.hyperledger.fabric.contract.ContractRouter'
13+
}
14+
```
15+
16+
## Contract Code
17+
18+
No changes are required to the contract code. Note that the previous 'bootstrap' main method is not required.
19+
20+
## Environment Variables
21+
22+
The setting of the `CHAINCODE_SERVER_ADDRESS` environment variable will trigger the code to work in the 'as-a-service' mode. This should be set to the hostname:port that the server will be exposed on. Typically this would be
23+
24+
```
25+
CHAINCODE_SERVER_ADDRESS=0.0.0.0:9999
26+
```
27+
28+
*NOTE* if `CHAINCODE_SERVER_ADDRESS` is set, and the chaincode is deployed as a regular chaincode, this will result in a failure. The chaincode will still start in 'as-a-service' mode.
29+
30+
The `CORE_CHAINCODE_ID_NAME` must also be set to match the ID used when deploying the chaincode.
31+
32+
*For TLS* ensure that
33+
- `CORE_PEERT_TLS_ENABLED` is true
34+
- `CORE_PEER_TLS_ROOTCERT_FILE` is set to the certificate of the root CA
35+
- `CORE_TLS_CLIENT_KEY_FILE` and `CORE_TLS_CLIENT_CERT_FILE` if using mutual TLS (PEM encoded)
36+
37+
38+
## Dockerfile
39+
40+
There is an example dockerfile that shows how the chaincode can be built into a container image.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

examples/fabric-contract-example-external/src/main/java/org/example/Application.java

Lines changed: 0 additions & 39 deletions
This file was deleted.

fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeBase.java

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import java.io.InputStream;
1616
import java.net.InetSocketAddress;
1717
import java.net.SocketAddress;
18+
import java.net.URI;
19+
import java.net.URISyntaxException;
1820
import java.nio.file.Files;
1921
import java.nio.file.Paths;
2022
import java.security.Security;
@@ -25,7 +27,9 @@
2527
import java.util.logging.Logger;
2628
import java.util.logging.SimpleFormatter;
2729

28-
import io.grpc.stub.StreamObserver;
30+
import com.google.protobuf.InvalidProtocolBufferException;
31+
import com.google.protobuf.util.JsonFormat;
32+
2933
import org.apache.commons.cli.CommandLine;
3034
import org.apache.commons.cli.DefaultParser;
3135
import org.apache.commons.cli.Options;
@@ -38,16 +42,14 @@
3842
import org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage;
3943
import org.hyperledger.fabric.shim.impl.ChaincodeSupportClient;
4044
import org.hyperledger.fabric.shim.impl.InvocationTaskManager;
41-
42-
import com.google.protobuf.InvalidProtocolBufferException;
43-
import com.google.protobuf.util.JsonFormat;
45+
import org.hyperledger.fabric.traces.Traces;
4446

4547
import io.grpc.ManagedChannelBuilder;
4648
import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts;
4749
import io.grpc.netty.shaded.io.grpc.netty.NegotiationType;
4850
import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder;
4951
import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext;
50-
import org.hyperledger.fabric.traces.Traces;
52+
import io.grpc.stub.StreamObserver;
5153

5254
/**
5355
* Abstract implementation of {@link Chaincode}.
@@ -348,21 +350,20 @@ private Level mapLevel(final String level) {
348350
}
349351

350352

351-
private SocketAddress parseHostPort(final String hostAddrStr) {
352-
String[] hostArr = hostAddrStr.split(":");
353-
String h;
354-
int p;
353+
private SocketAddress parseHostPort(final String hostAddrStr) throws URISyntaxException {
355354

356-
if (hostArr.length == 2) {
357-
p = Integer.valueOf(hostArr[1].trim());
358-
h = hostArr[0].trim();
359-
} else {
360-
final String msg = String.format(
361-
"peer address argument should be in host:port format, current %s in wrong", hostAddrStr);
362-
LOGGER.severe(msg);
363-
throw new IllegalArgumentException(msg);
355+
// WORKAROUND: add any scheme to make the resulting URI valid.
356+
URI uri = new URI("my://" + hostAddrStr); // may throw URISyntaxException
357+
String host = uri.getHost();
358+
int port = uri.getPort();
359+
360+
if (uri.getHost() == null || uri.getPort() == -1) {
361+
throw new URISyntaxException(uri.toString(),
362+
"URI must have host and port parts");
364363
}
365-
return new InetSocketAddress(h, p);
364+
365+
// validation succeeded
366+
return new InetSocketAddress(host, port);
366367
}
367368

368369
/**
@@ -530,7 +531,7 @@ public Properties getChaincodeConfig() {
530531
*
531532
* @return ChaincodeServerProperties populated
532533
*/
533-
public final ChaincodeServerProperties getChaincodeServerConfig() {
534+
public final ChaincodeServerProperties getChaincodeServerConfig() throws URISyntaxException {
534535
ChaincodeServerProperties chaincodeServerProperties = new ChaincodeServerProperties();
535536

536537
chaincodeServerProperties.setServerAddress(parseHostPort(chaincodeServerAddress));

fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeServerImplTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.junit.jupiter.api.Test;
1515

1616
import java.io.IOException;
17+
import java.net.URISyntaxException;
1718

1819
class ChaincodeServerImplTest {
1920
@Rule
@@ -82,7 +83,7 @@ void startAndStop() {
8283
}
8384

8485
chaincodeServer.stop();
85-
} catch (IOException e) {
86+
} catch (IOException | URISyntaxException e) {
8687
e.printStackTrace();
8788
}
8889
}

fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/NettyGrpcServerTest.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.junit.jupiter.api.Test;
1717

1818
import java.io.IOException;
19+
import java.net.URISyntaxException;
1920
import java.util.Properties;
2021

2122
class NettyGrpcServerTest {
@@ -50,7 +51,7 @@ void initNoTls() {
5051
final ChaincodeBase chaincodeBase = new EmptyChaincode();
5152
chaincodeBase.processEnvironmentOptions();
5253
ChaincodeServer chaincodeServer = new NettyChaincodeServer(chaincodeBase, chaincodeBase.getChaincodeServerConfig());
53-
} catch (IOException e) {
54+
} catch (IOException | URISyntaxException e) {
5455
e.printStackTrace();
5556
}
5657
}
@@ -172,7 +173,7 @@ void initEnvNotSet() {
172173
}
173174

174175
@Test
175-
void initEnvSetPortChaincodeServerAndCoreChaincodeIdName() throws IOException {
176+
void initEnvSetPortChaincodeServerAndCoreChaincodeIdName() throws IOException, URISyntaxException {
176177
clearEnv();
177178
environmentVariables.set("CORE_CHAINCODE_ID_NAME", "mycc");
178179
environmentVariables.set("CHAINCODE_SERVER_ADDRESS", "0.0.0.0:9999");
@@ -214,7 +215,7 @@ void startAndStopSetCoreChaincodeIdName() {
214215
}
215216

216217
chaincodeServer.stop();
217-
} catch (IOException e) {
218+
} catch (IOException | URISyntaxException e) {
218219
e.printStackTrace();
219220
}
220221
}
@@ -239,7 +240,7 @@ void startAndStop() {
239240
}
240241

241242
chaincodeServer.stop();
242-
} catch (IOException e) {
243+
} catch (IOException | URISyntaxException e) {
243244
e.printStackTrace();
244245
}
245246
}
@@ -269,7 +270,7 @@ void startAndStopTlsPassword() {
269270
}
270271

271272
chaincodeServer.stop();
272-
} catch (IOException e) {
273+
} catch (IOException | URISyntaxException e) {
273274
e.printStackTrace();
274275
}
275276
}
@@ -298,7 +299,7 @@ void startAndStopTlsWithoutPassword() {
298299
}
299300

300301
chaincodeServer.stop();
301-
} catch (IOException e) {
302+
} catch (IOException | URISyntaxException e) {
302303
e.printStackTrace();
303304
}
304305
}

0 commit comments

Comments
 (0)