Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.sap.cloud.sdk.odatav2.connectivity.impl.ODataCreateRequestImpl Maven / Gradle / Ivy
/*******************************************************************************
* (c) 201X SAP SE or an SAP affiliate company. All rights reserved.
******************************************************************************/
package com.sap.cloud.sdk.odatav2.connectivity.impl;
import static com.sap.cloud.sdk.odatav2.connectivity.internal.ODataConnectivityUtil.*;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.entity.StringEntity;
import org.apache.olingo.odata2.api.edm.Edm;
import org.apache.olingo.odata2.api.edm.EdmAssociationSet;
import org.apache.olingo.odata2.api.edm.EdmAssociationSetEnd;
import org.apache.olingo.odata2.api.edm.EdmEntitySet;
import org.apache.olingo.odata2.api.edm.EdmEntityType;
import org.apache.olingo.odata2.api.edm.EdmException;
import org.apache.olingo.odata2.api.edm.EdmNavigationProperty;
import org.apache.olingo.odata2.api.ep.EntityProviderException;
import org.apache.olingo.odata2.api.ep.entry.ODataEntry;
import org.apache.olingo.odata2.api.processor.ODataResponse;
import org.apache.olingo.odata2.client.api.ODataClient;
import org.apache.olingo.odata2.client.api.ep.DeserializerProperties;
import org.apache.olingo.odata2.client.api.ep.Entity;
import org.apache.olingo.odata2.client.api.ep.EntitySerializerProperties;
import org.apache.olingo.odata2.client.api.ep.EntityStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sap.cloud.sdk.cloudplatform.cache.CacheKey;
import com.sap.cloud.sdk.cloudplatform.connectivity.HttpClientAccessor;
import com.sap.cloud.sdk.cloudplatform.connectivity.WithDestinationName;
import com.sap.cloud.sdk.odatav2.connectivity.ErrorResultHandler;
import com.sap.cloud.sdk.odatav2.connectivity.ODataCreateRequest;
import com.sap.cloud.sdk.odatav2.connectivity.ODataCreateResult;
import com.sap.cloud.sdk.odatav2.connectivity.ODataException;
import com.sap.cloud.sdk.odatav2.connectivity.ODataExceptionType;
import com.sap.cloud.sdk.odatav2.connectivity.cache.metadata.GuavaMetadataCache;
import com.sap.cloud.sdk.odatav2.connectivity.cache.metadata.MetadataCache;
import com.sap.cloud.sdk.odatav2.connectivity.internal.EdmWithCSRF;
import com.sap.cloud.sdk.odatav2.connectivity.internal.ODataConnectivityUtil;
public class ODataCreateRequestImpl implements ODataCreateRequest {
private static Logger logger = LoggerFactory.getLogger(ODataCreateRequestImpl.class);
private static final String APPLICATION_JSON = "application/json";
private static final String UTF_8 = "UTF-8";
private static MetadataCache metadataCache = new GuavaMetadataCache();
public static final String AUTHORIZATION_HEADER = "Authorization";
private Boolean entityCreated = false;
String location = null;
/**
* Content Type Constants
*/
public static final String CONTENT_TYPE = "Content-Type";
public static final String ACCEPT_HEADER = "Accept";
public static final String CONTENTTYPE_ATOM_XML = "application/xml";
private String serviceName;
private String entitySet;
private Map body;
private ErrorResultHandler> errorHandler;
private Map headers;
private Map destinationRelevantHeaders;
private Boolean cacheMetadata;
private String navigationProperty = null;
private Map srcKeyMap = null;
private URL metadataFilePath;
private CacheKey cacheKey;
private Boolean isCacheRefresh;
/*
* Constructor for Create Via Navigation
* */
public ODataCreateRequestImpl(String serviceName, String entitySetName, Map body, String navigationProperty, Map srcKeyMap,
ErrorResultHandler> errorHandler, Map headers,
Map destinationRelevantHeaders, Boolean cacheMetadata, URL metadataFilePath,CacheKey cacheKey, Boolean isCacheRefresh) {
this.serviceName = serviceName;
this.entitySet = entitySetName;
this.body = body;
this.srcKeyMap = srcKeyMap ;
this.navigationProperty = navigationProperty;
this.errorHandler = errorHandler;
this.headers = headers;
this.destinationRelevantHeaders = destinationRelevantHeaders;
this.cacheMetadata = cacheMetadata;
this.metadataFilePath = metadataFilePath;
this.cacheKey = cacheKey;
this.isCacheRefresh = isCacheRefresh;
}
/*
* Constructor for Simple Create
* */
public ODataCreateRequestImpl(String serviceName, String entitySetName, Map body,
ErrorResultHandler> errorHandler, Map headers,
Map destinationRelevantHeaders, Boolean cacheMetadata, URL metadataFilePath,CacheKey cacheKey, boolean isCacheRefresh) {
this.serviceName = serviceName;
this.entitySet = entitySetName;
this.body = body;
this.errorHandler = errorHandler;
this.headers = headers;
this.destinationRelevantHeaders = destinationRelevantHeaders;
this.cacheMetadata = cacheMetadata;
this.metadataFilePath = metadataFilePath;
this.cacheKey = cacheKey;
this.isCacheRefresh = isCacheRefresh;
}
String getServiceName() {
return serviceName;
}
String getEntitySet() {
return entitySet;
}
Map getBody() {
return body;
}
Map getHeaders() {
return headers;
}
String getNavigationProperty() {
return navigationProperty;
}
@Override
public ODataCreateResult execute(String destinationName) throws ODataException {
logger.debug("Create Called with Destination Name: " + destinationName);
return handleExecute(null, destinationName);
}
public ODataCreateResult getResponseFromLocation(String completeUrl, String destinationName) throws ODataException {
HttpResponse httpResponse = null;
try {
Edm edm = metadataCache.getEdm(completeUrl, getHttpClient(destinationName), destinationRelevantHeaders,
errorHandler, cacheMetadata,metadataFilePath,cacheKey,isCacheRefresh);
EdmEntitySet eSet = edm.getDefaultEntityContainer().getEntitySet(this.entitySet);
HttpGet requestGet = new HttpGet(location);
httpResponse = getHttpClient(destinationName).execute(requestGet);
ODataConnectivityUtil.checkHttpStatus(httpResponse, errorHandler);
EntityStream entityStream = new EntityStream();
entityStream.setContent(httpResponse.getEntity().getContent());
entityStream.setReadProperties(DeserializerProperties.init().build());
String contentType = "application/atom+xml";
if (!httpResponse.getFirstHeader("Content-Type").toString().contains(contentType))
contentType = "application/json";
ODataEntry deepInsResponse = ODataClient.newInstance().createDeserializer(contentType).readEntry(eSet,
entityStream);
return new ODataCreateResult(httpResponse, deepInsResponse.getProperties());
} catch (IOException e1) {
HttpClientUtils.closeQuietly(httpResponse);
throw new ODataException(null, "IOException", e1);
} catch (EntityProviderException | EdmException e1) {
HttpClientUtils.closeQuietly(httpResponse);
throw new ODataException(ODataExceptionType.RESPONSE_DESERIALIZATION_FAILED,
"Error during serialization of input payload. " + e1.getMessage(), e1);
} finally {
HttpClientUtils.closeQuietly(httpResponse);
}
}
private boolean isNavigationFlow(){
return (navigationProperty == null) ? false: true;
}
ODataCreateResult create(HttpClient httpClient) throws ODataException {
String serviceUri = this.serviceName;
String entitySetName = this.entitySet;
String completeUrl = null;
completeUrl = serviceUri + "/" + entitySetName;
HttpResponse httpResponse = null;
String contentType = APPLICATION_JSON;
// To get the EdmEntitySet Object
// Get the edm object first.
Edm edm = null;
ODataResponse response = null;
Entity entity = null;
EdmWithCSRF edmWithCSRF = null;
try {
edmWithCSRF = ODataConnectivityUtil.readMetadataWithCSRF(serviceUri, httpClient, destinationRelevantHeaders,
errorHandler, cacheMetadata,metadataFilePath,cacheKey,isCacheRefresh);
} catch (IOException e1) {
throw new ODataException(ODataExceptionType.METADATA_FETCH_FAILED, "Metadata fetch failed!", e1);
}
if (edmWithCSRF == null || edmWithCSRF.getEdm() == null) {
throw new ODataException(ODataExceptionType.METADATA_FETCH_FAILED, "Metadata fetch failed!", null);
}
edm = edmWithCSRF.getEdm();
EdmEntitySet eSet;
EdmEntityType entityType;
EdmEntityType childEntityType = null;
EdmEntitySet targetEtySet = null;
EdmNavigationProperty navigationProperty = null;
boolean isNavigationFlow = isNavigationFlow();
try {
eSet = edm.getDefaultEntityContainer().getEntitySet(entitySetName);
if (eSet == null)
throw new ODataException(ODataExceptionType.INVALID_ENTITY_NAME,
"No entity with name " + entitySetName + " in the OData service", null);
entityType = eSet.getEntityType();
if(isNavigationFlow)
navigationProperty = getNavigationProperty(eSet);
if(navigationProperty!=null){
// Find Target Type and Set for Navigation
childEntityType = getTargetEntityType(edm, eSet ,navigationProperty);
//Must have association set
targetEtySet = getTargetEntitySet(edm, eSet , navigationProperty);
}
if(childEntityType!=null) {
//for Create via Navigation
entity = ODataConnectivityUtil.addPropertiesToEntity(this.body, childEntityType);
}
else
//for Simple Create
entity = ODataConnectivityUtil.addPropertiesToEntity(this.body, entityType);
completeUrl = handleNavigation(completeUrl,entityType);
} catch (EdmException e) {
throw new ODataException(ODataExceptionType.METADATA_PARSING_FAILED, "Error while parsing the metadata.",
e);
}
HttpPost requestPost = new HttpPost(completeUrl);
// Set CSRF Token Header.
requestPost.setHeader(ODataConnectivityUtil.CSRF_HEADER, edmWithCSRF.getCsrfToken());
// Set Content-Type header
requestPost.setHeader(CONTENT_TYPE, contentType);
requestPost.setHeader(ACCEPT_HEADER, contentType);
for (Entry header : headers.entrySet()) {
requestPost.setHeader(header.getKey(), header.getValue());
}
entity.setWriteProperties(EntitySerializerProperties.serviceRoot(URI.create(serviceUri)).build());
try {
//Target EntitySet via navigation vs directEntityset
eSet = (targetEtySet!=null) ? targetEtySet: eSet;
response = ODataClient.newInstance().createSerializer(contentType).writeEntry(eSet, entity);
} catch (EntityProviderException e) {
throw new ODataException(ODataExceptionType.INPUT_DATA_SERIALIZATION_FAILED,
"Error during serialization of input payload. " + e.getMessage(), e);
}
byte[] contentArray = null;
try {
InputStream inputStream = ODataConnectivityUtil.getObjectStream(response.getEntity());
String entityString = null;
if (inputStream != null) {
entityString = getEntityString(inputStream);
closeStream(inputStream);
}
StringEntity postEntity = new StringEntity(entityString, UTF_8);
requestPost.setEntity(postEntity);
httpResponse = httpClient.execute(requestPost);
if (httpResponse.getStatusLine().getStatusCode() == 201) {
entityCreated = true;
location = httpResponse.getFirstHeader("Location").getValue();
}
ODataConnectivityUtil.checkHttpStatus(httpResponse, errorHandler);
contentArray = IOUtils.toByteArray(httpResponse.getEntity().getContent());
EntityStream entityStream = new EntityStream();
entityStream.setContent(new ByteArrayInputStream(contentArray));
entityStream.setReadProperties(DeserializerProperties.init().build());
ODataEntry deepInsResponse = ODataClient.newInstance().createDeserializer(contentType).readEntry(eSet,
entityStream);
return new ODataCreateResult(httpResponse, deepInsResponse.getProperties());
} catch (EntityProviderException e) {
//to support response which has results as array CAP #3505
if(contentArray != null) {
ODataEntry deepInsResponse;
InputStream contentStream = null;
try {
String contentStr = new String(contentArray, StandardCharsets.UTF_8);
contentStr = contentStr.replaceFirst("\\[", "");
int lastIndex = contentStr.lastIndexOf("]");
contentStr = contentStr.substring(0, lastIndex) + contentStr.substring(lastIndex+1);
contentStream = IOUtils.toInputStream(contentStr, StandardCharsets.UTF_8);
EntityStream entityStream = new EntityStream();
entityStream.setContent(contentStream);
entityStream.setReadProperties(DeserializerProperties.init().build());
deepInsResponse = ODataClient.newInstance().createDeserializer(contentType).readEntry(eSet,
entityStream);
} catch (EntityProviderException e1) {
throw new ODataException(ODataExceptionType.RESPONSE_DESERIALIZATION_FAILED,
"Error while deserializing response. " + e.getMessage(), e);
}finally {
closeStream(contentStream);
}
return new ODataCreateResult(httpResponse, deepInsResponse.getProperties());
}else {
throw new ODataException(ODataExceptionType.RESPONSE_DESERIALIZATION_FAILED,
"Error while deserializing response. " + e.getMessage(), e);
}
} catch (IllegalStateException | IOException e) {
throw new ODataException(null, e.getMessage(), e);
} finally {
ODataConnectivityUtil.closeQuietly(httpResponse, requestPost);
}
}
private void closeStream(InputStream contentStream) {
if(contentStream != null) {
try {
contentStream.close();
} catch (IOException ex) {
logger.error("Error while closing the inputstream", ex);
}
}
}
public EdmNavigationProperty getNavigationProperty(EdmEntitySet srcEtySet) throws EdmException{
if(srcKeyMap == null || navigationProperty== null || srcKeyMap.isEmpty())
return null;
EdmEntityType srcEtytype = srcEtySet.getEntityType();
EdmNavigationProperty navigationProp = (EdmNavigationProperty) srcEtytype.getProperty(navigationProperty) ;
return navigationProp;
}
private EdmEntityType getTargetEntityType(Edm edm, EdmEntitySet srcEtySet ,EdmNavigationProperty navigationProp) throws EdmException {
if(navigationProp == null)
return null ;
else {
//Look for Target Entity Type based on Navigation Property
String toRole = navigationProp.getToRole() ;
return navigationProp.getRelationship().getEnd(toRole).getEntityType();
}
}
public EdmEntitySet getTargetEntitySet(Edm edm, EdmEntitySet srcEtySet, EdmNavigationProperty navigationProp) throws EdmException, ODataException{
//Look for Target EntitySet Type based on Navigation Property --> Association --> AssociationSet
EdmAssociationSet associationSet = null;
associationSet = edm.getDefaultEntityContainer().getAssociationSet(srcEtySet, navigationProp );
if(associationSet == null){
throw new ODataException( ODataExceptionType.METADATA_PARSING_FAILED, "The association, referred by the navigation property "+ navigationProp.getName() + ", is not contained in an association set.");
}
EdmAssociationSetEnd end = null;
if(navigationProp!= null){
end = associationSet.getEnd(navigationProp.getToRole()) ;
return end.getEntitySet() ;
}
return null;
}
public String handleNavigation(String completeUrl, EdmEntityType entityType) throws EdmException, ODataException {
//Construct URL
if(srcKeyMap == null || navigationProperty== null || srcKeyMap.isEmpty() )
return completeUrl;
else
//Construct URL for Key in Parent Entity
return completeUrl + '(' + ODataConnectivityUtil.convertKeyValuesToString(srcKeyMap, entityType ) + ')'+'/'+navigationProperty;
}
protected HttpClient getHttpClient(String destinationName) {
return HttpClientAccessor.getHttpClient(destinationName);
}
private String getEntityString(InputStream stream) {
StringBuilder sb = new StringBuilder();
String line;
try (BufferedReader br = new BufferedReader(new InputStreamReader(stream, Charset.forName(UTF_8)))) {
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append("\n");
}
} catch (IOException e) {
}
return sb.toString();
}
@Override
public ODataCreateResult execute(WithDestinationName withDestinationName) throws ODataException {
return execute(withDestinationName.getDestinationName());
}
@Override
public ODataCreateResult execute(HttpClient providedClient) throws ODataException {
logger.debug("Create Called with Direct URL");
return handleExecute(providedClient, null);
}
private ODataCreateResult handleExecute(HttpClient httpClient, String destinationName) throws ODataException {
ODataCreateResult result = null;
httpClient = destinationName == null ? httpClient : getHttpClient(destinationName);
if (cacheMetadata) {
try {
result = create(httpClient);
} catch (ODataException e) {
if (e.getODataExceptionType().equals(ODataExceptionType.OTHER)
|| e.getODataExceptionType().equals(ODataExceptionType.ODATA_OPERATION_EXECUTION_FAILED)) {
throw e;
} else {
String completeUrl = this.serviceName + "/$metadata";
this.isCacheRefresh = true;// set the isCacheRefresh to true so the entry in the cache is removed for the particular cacheKey.
if (entityCreated && location != null) {
return getResponseFromLocation(completeUrl, null);
} else {
throw e;
}
}
}
} else {
result = create(httpClient);
}
return result;
}
@Override
public String toString() {
return "CREATE " + withSeparator(SEPARATOR_PATH, serviceName, entitySet);
}
}