All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sap.cloud.sdk.services.scp.blockchain.hyperledgerfabric.FabricService Maven / Gradle / Ivy

/*
 * Copyright (c) 2019 SAP SE or an SAP affiliate company. All rights reserved.
 */

package com.sap.cloud.sdk.services.scp.blockchain.hyperledgerfabric;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Nonnull;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;

import com.google.common.annotations.Beta;
import com.google.common.base.Strings;
import com.google.gson.Gson;
import com.google.gson.JsonIOException;
import com.sap.cloud.sdk.cloudplatform.connectivity.HttpClientAccessor;
import com.sap.cloud.sdk.cloudplatform.connectivity.HttpEntityUtil;
import com.sap.cloud.sdk.cloudplatform.connectivity.ScpCfService;
import com.sap.cloud.sdk.cloudplatform.connectivity.exception.HttpClientInstantiationException;
import com.sap.cloud.sdk.cloudplatform.exception.CloudPlatformException;
import com.sap.cloud.sdk.cloudplatform.exception.ShouldNotHappenException;

import lombok.extern.slf4j.Slf4j;

/**
 * SAP Cloud Platform Blockchain using Hyperledger Fabric adapter service. Facilitates access to chaincode interfaces.
 * 

* Be aware that this class is in Beta (as indicated by the annotation) and therefore subject to breaking changes. *

*/ @Beta @Slf4j public class FabricService { private final ScpCfService cfService; private final String serviceUrl; private FabricService( final ScpCfService cfService ) throws CloudPlatformException { this.cfService = cfService; if( cfService.getServiceLocationInfo() == null ) { throw new CloudPlatformException("Missing service location info on given service: " + cfService); } serviceUrl = cfService.getServiceLocationInfo(); } /** * Create a service instance looking for an instance of service type 'hyperledger-fabric'. * * @return the new instance * @throws CloudPlatformException * if service information cannot be found or is incompletely specified */ @Nonnull public static FabricService create() throws CloudPlatformException { return getFabricService("hyperledger-fabric"); } /** * Access a function exposed by a chaincode. * * @param invocationType * lightweight query or transaction via invoke. * @param chainCodeId * identifying the chain code. * @param function * the name of the function to be invoked. * @param params * parameters to the function call. * * @return the string response returned by the function, decoded as UTF-8 string. * * @throws IllegalArgumentException * if the chaincodeId argument contains whitespace. * @throws FabricServiceFailureException * if the service invocation fails. * @throws JsonIOException * if the encoding of the request fails. * @throws CloudPlatformException * if there is a problem authorizing the access. */ @Nonnull public String invokeOrQuery( @Nonnull final FabricInvocationType invocationType, @Nonnull final String chainCodeId, @Nonnull final String function, @Nonnull final String... params ) throws FabricServiceFailureException, IllegalArgumentException, JsonIOException, CloudPlatformException { final List argsList = Arrays.asList(params); if( log.isTraceEnabled() ) { log.trace("{} {}:{}({})", invocationType, chainCodeId, function, argsList); } else { log.debug("{} {}:{}", invocationType, chainCodeId, function); } if( Strings.isNullOrEmpty(chainCodeId) || chainCodeId.matches(".*\\s.*") ) { throw new IllegalArgumentException("Given chaincode id invalid - empty string or contains whitespace"); } final HttpPost chaincodeEndpointRequest; try { chaincodeEndpointRequest = new HttpPost( new URI( getServiceUrl() + "/chaincodes/" + chainCodeId + "/latest/" + invocationType.getPathParamValue()).normalize()); } catch( final URISyntaxException e ) { throw new ShouldNotHappenException("URL for accessing fabric service problematic: " + e.getMessage(), e); } cfService.addBearerTokenHeader(chaincodeEndpointRequest); chaincodeEndpointRequest.setHeader("Accept", "application/json;charset=UTF-8"); final Map requestBody = new LinkedHashMap<>(); requestBody.put("function", function); requestBody.put("arguments", argsList); requestBody.put("async", false); final String json; try { json = new Gson().toJson(requestBody); } catch( final JsonIOException e ) { log.debug("Could not encode request: " + e); throw e; } log.trace("Request to be sent: {}", json); chaincodeEndpointRequest.setEntity(new StringEntity(json, ContentType.APPLICATION_JSON)); // Overriding the content type to NOT contain the charset is required due to bug in (newer?) Fabric services chaincodeEndpointRequest.setHeader("Content-Type", "application/json"); try { final HttpResponse response = HttpClientAccessor.getHttpClient().execute(chaincodeEndpointRequest); final StatusLine statusLine = response.getStatusLine(); final String responseBody = HttpEntityUtil.getResponseBody(response); if( responseBody == null ) { throw new FabricServiceFailureException( "Failed to execute request to function " + function + ": no body returned in response."); } if( log.isTraceEnabled() ) { log.trace("Response status: {}, content: {}", statusLine, responseBody); } else { log.debug("Response status: {}", statusLine); } switch( statusLine.getStatusCode() ) { case HttpStatus.SC_OK: return responseBody; default: throw new FabricServiceFailureException( "Failed to execute request to function " + function + ": " + "Service request failed with status: " + statusLine + "."); } } catch( final IOException | HttpClientInstantiationException e ) { final String message = "Failed to execute request to function " + function + ": " + e.getMessage(); log.debug(message, e); throw new FabricServiceFailureException(message, e); } finally { chaincodeEndpointRequest.releaseConnection(); } } static FabricService getFabricService( @Nonnull final String serviceType ) throws CloudPlatformException { final ScpCfService cfService = ScpCfService.of( serviceType, null, "credentials/oAuth/url", "credentials/oAuth/clientId", "credentials/oAuth/clientSecret", "credentials/serviceUrl"); return new FabricService(cfService); } /** * Access to the Fabric service root URL. * * @return the url */ @Nonnull public String getServiceUrl() { return serviceUrl; } @Override @Nonnull public String toString() { return "FabricService{" + "cfService=" + cfService + '}'; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy