Skip to content

Instantly share code, notes, and snippets.

@DazWilkin
Created November 23, 2017 18:38
Show Gist options
  • Save DazWilkin/d03b47a50bb02c3d0ffb7614b50064b4 to your computer and use it in GitHub Desktop.
Save DazWilkin/d03b47a50bb02c3d0ffb7614b50064b4 to your computer and use it in GitHub Desktop.
Deploy ‘fabcar’ on Corda
package com.template;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import net.corda.core.messaging.CordaRPCOps;
import net.corda.core.messaging.FlowProgressHandle;
import net.corda.core.node.NodeInfo;
import net.corda.core.identity.CordaX500Name;
import net.corda.core.identity.Party;
import net.corda.core.contracts.StateAndRef;
import net.corda.core.transactions.SignedTransaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import static java.util.stream.Collectors.toList;
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
import static javax.ws.rs.core.Response.Status.CREATED;
@Path("fabcar")
public class CarApi {
private final CordaRPCOps rpcOps;
private final CordaX500Name myLegalName;
private final List<String> serviceNames = ImmutableList.of("Controller", "Network Map Service");
static private final Logger logger = LoggerFactory.getLogger(CarApi.class);
public CarApi(CordaRPCOps services) {
this.rpcOps = services;
this.myLegalName = rpcOps
.nodeInfo()
.getLegalIdentities()
.get(0)
.getName();
}
@GET
@Path("peers")
@Produces(MediaType.APPLICATION_JSON)
public Map<String, List<CordaX500Name>> getPeers() {
List<NodeInfo> nodeInfoSnapshot = rpcOps.networkMapSnapshot();
return ImmutableMap.of("peers", nodeInfoSnapshot
.stream()
.map(node -> node.getLegalIdentities().get(0).getName())
.filter(name -> !name.equals(myLegalName) && !serviceNames.contains(name.getOrganisation()))
.collect(toList()));
}
@GET
@Path("cars")
@Produces(MediaType.APPLICATION_JSON)
public List<StateAndRef<CarState>> getCars() {
return rpcOps.vaultQuery(CarState.class).getStates();
}
@PUT
@Path("changeCarOwner")
public Response changeCarOwner(
@QueryParam("color") String color,
@QueryParam("make") String make,
@QueryParam("model") String model,
@QueryParam("newOwner") CordaX500Name newOwnerX500
) throws InterruptedException, ExecutionException {
if (newOwnerX500 == null) {
return Response
.status(BAD_REQUEST)
.entity("Query parameter 'newOwner' missing or has wrong format.\n")
.build();
}
final Party newOwner = rpcOps.wellKnownPartyFromX500Name(newOwnerX500);
try {
FlowProgressHandle<SignedTransaction> flowHandle = rpcOps
.startTrackedFlowDynamic(CarFlow.class, color, make, model, newOwner);
flowHandle
.getProgress()
.subscribe(evt -> System.out.printf(">> %s\n", evt));
final SignedTransaction result = flowHandle
.getReturnValue()
.get();
final String msg = String.format("Transaction id %s committed to ledger.\n", result.getId());
return Response
.status(CREATED)
.entity(msg)
.build();
} catch (Throwable ex) {
final String msg = ex.getMessage();
logger.error(ex.getMessage(), ex);
return Response
.status(BAD_REQUEST)
.entity(msg)
.build();
}
}
}
package com.template;
import co.paralleluniverse.fibers.Suspendable;
import net.corda.core.contracts.Command;
import net.corda.core.contracts.CommandData;
import net.corda.core.flows.*;
import net.corda.core.identity.Party;
import net.corda.core.transactions.SignedTransaction;
import net.corda.core.transactions.TransactionBuilder;
import net.corda.core.utilities.ProgressTracker;
import static com.template.TemplateContract.TEMPLATE_CONTRACT_ID;
@InitiatingFlow
@StartableByRPC
public class CarFlow extends FlowLogic<SignedTransaction> {
private final String color;
private final String make;
private final String model;
private final Party newOwner;
private final ProgressTracker progressTracker = new ProgressTracker();
public CarFlow(String color, String make, String model, Party newOwner) {
this.color = color;
this.make = make;
this.model = model;
this.newOwner = newOwner;
}
@Suspendable
@Override
public SignedTransaction call() throws FlowException {
final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);
CarState outputState = new CarState(color, make, model, newOwner);
CommandData cmdType = new TemplateContract.Commands.Action();
Command cmd = new Command<>(cmdType, getOurIdentity().getOwningKey());
final TransactionBuilder txBuilder = new TransactionBuilder(notary)
.addOutputState(outputState, TEMPLATE_CONTRACT_ID)
.addCommand(cmd);
final SignedTransaction signedTx = getServiceHub().signInitialTransaction(txBuilder);
subFlow(new FinalityFlow(signedTx));
return null;
}
}
package com.template;
import com.google.common.collect.ImmutableList;
import net.corda.core.contracts.ContractState;
import net.corda.core.identity.AbstractParty;
import net.corda.core.identity.Party;
import java.util.Collections;
import java.util.List;
public class CarState implements ContractState {
private final String color;
private final String make;
private final String model;
private final Party owner;
public CarState(String color, String make, String model, Party owner) {
this.color = color;
this.make = make;
this.model = model;
this.owner = owner;
}
public String getColor() {
return this.color;
}
public String getMake() {
return this.make;
}
public String getModel() {
return this.model;
}
public Party getOwner() {
return this.owner;
}
@Override
public List<AbstractParty> getParticipants() {
return ImmutableList.of(owner);
}
}
package com.template;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import net.corda.core.messaging.CordaRPCOps;
import net.corda.webserver.services.WebServerPluginRegistry;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
public class TemplateWebPlugin implements WebServerPluginRegistry {
@NotNull
@Override
public List<Function<CordaRPCOps, ?>> getWebApis() {
return ImmutableList.of(CarApi::new);
}
@NotNull
@Override
public Map<String, String> getStaticServeDirs() {
return ImmutableMap.of(
// This will serve the templateWeb directory in resources to /web/template
"template", getClass().getClassLoader().getResource("templateWeb").toExternalForm());
}
@Override
public void customizeJSONSerialization(ObjectMapper objectMapper) {
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment