All Downloads are FREE. Search and download functionalities are using the official Maven repository.
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.ODataQueryResult Maven / Gradle / Ivy
/*******************************************************************************
* (c) 201X SAP SE or an SAP affiliate company. All rights reserved.
******************************************************************************/
package com.sap.cloud.sdk.odatav2.connectivity;
import static com.sap.cloud.sdk.odatav2.connectivity.ODataGsonBuilder.newGsonBuilder;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.http.HttpResponse;
import org.apache.olingo.odata2.api.edm.EdmEntitySet;
import org.apache.olingo.odata2.api.ep.EntityProvider;
import org.apache.olingo.odata2.api.ep.EntityProviderException;
import org.apache.olingo.odata2.api.ep.EntityProviderReadProperties;
import org.apache.olingo.odata2.api.ep.entry.ODataEntry;
import org.apache.olingo.odata2.api.ep.feed.ODataFeed;
import org.slf4j.Logger;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.common.base.Optional;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.stream.JsonReader;
import com.sap.cloud.sdk.cloudplatform.logging.CloudLoggerFactory;
import com.sap.cloud.sdk.odatav2.connectivity.internal.ODataHttpResponseWrapper;
import com.sap.cloud.sdk.result.CollectedResultCollection;
import com.sap.cloud.sdk.result.DefaultCollectedResultCollection;
import com.sap.cloud.sdk.result.GsonResultElementFactory;
import com.sap.cloud.sdk.result.ResultElement;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
@Data
public class ODataQueryResult extends ODataHttpResponseWrapper implements Iterable {
private static final Logger logger = CloudLoggerFactory.getLogger(ODataQuery.class);
private static final String APPLICATION_JSON = "application/json";
private String streamData;
private HttpResponse httpResponse;
private EdmEntitySet entitySet;
private ResultElement resultElement;
private boolean hasResultElement = false;
String contentType = APPLICATION_JSON;
InputStream istream;
Integer inlineCount = null;
boolean inlineCountAlreadyCalculated = false;
byte[] buffer;
@Getter
@Setter
@JsonIgnore
private ODataQuery query;
ODataQueryResult(EdmEntitySet eset, HttpResponse httpResponse, boolean isMediaRequest)throws IllegalStateException, IOException{
this.httpResponse = httpResponse;
if(!isMediaRequest){
this.streamData = inputStreamToString();
}
this.entitySet = eset;
setResponse(httpResponse);
}
public ODataQueryResult(String streamData, Map> headerMap, int statusCode, EdmEntitySet eset){
this.entitySet =eset;
this.streamData = streamData;
this.responseStatusCode = statusCode;
this.headersMap =headerMap;
}
/**
* Constructs ODataQueryResult object
* Provides support for asMap and asListOfMaps APIs along with as and asList APIs support
* @param eset
* @param httpResponse
* @throws IOException
*/
public ODataQueryResult(EdmEntitySet eset, HttpResponse httpResponse) throws IllegalStateException, IOException{
this(eset, httpResponse, false);
}
/**
* Constructs ODataQueryResult object
* @param resultElmnt HttpResponse data parsed into JSON
* @param httpResponse has response data
*
* {will be removed in next version}
* use {@link #EdmEntitySet edmEntitySet} instead like this:
*
*
*
* ODataQueryResult(edmEntitySet, httpResponse)
*
*
*/
@Deprecated
public ODataQueryResult(ResultElement resultElmnt, HttpResponse httpResponse) throws IllegalStateException, IOException {
this.httpResponse = httpResponse;
this.streamData = inputStreamToString();
this.resultElement = resultElmnt;
this.hasResultElement = true;
setResponse(httpResponse);
}
private String inputStreamToString() {
ByteArrayOutputStream result = new ByteArrayOutputStream();
buffer = new byte[1024];
int length;
InputStream inputStream;
try {
inputStream = httpResponse.getEntity().getContent();
while ((length = inputStream.read(buffer)) != -1) {
result.write(buffer, 0, length);
}
return result.toString("UTF-8");
} catch (IllegalStateException | IOException e) {
logger.error("Failed to convert inputsteam into string" + e.getMessage());
}
return null;
}
private InputStream stringToInputStream() throws UnsupportedEncodingException {
InputStream stream = null;
if(streamData != null)
stream = new ByteArrayInputStream(this.streamData.getBytes("UTF-8"));
return stream;
}
private ResultElement loadEntriesFromResponse() {
ResultElement result = null;
if(this.streamData != null) {
JsonElement responseElement = new JsonParser().parse(this.streamData);
JsonObject resultContainer = responseElement.getAsJsonObject().getAsJsonObject("d");
if (inlineCount == null) {
if (resultContainer.has("__count"))
inlineCount = resultContainer.getAsJsonPrimitive("__count").getAsInt();
inlineCountAlreadyCalculated = true;
}
GsonResultElementFactory resultElementFactory = new GsonResultElementFactory(newGsonBuilder());
if (resultContainer.has("results")) {
result = resultElementFactory.create(resultContainer.getAsJsonArray("results"));
} else {
result = resultElementFactory.create(resultContainer);
}
}
return result;
}
public List asListOfResultData() {
List result = new LinkedList();
JsonReader reader;
JsonElement jsonElement = null;
String etag = null;
InputStream inputStream = null;
try {
if (buffer == null) {
inputStream = stringToInputStream();
} else {
inputStream = new ByteArrayInputStream(buffer);
}
if(inputStream != null) {
reader = new JsonReader(new InputStreamReader(inputStream ));
reader.beginObject();
reader.nextName();
final Gson gson = newGsonBuilder().create();
if (streamData.contains("results")) {
reader.beginObject();
if (reader.nextName().equals("results")) {
reader.beginArray();
while (reader.hasNext()) {
jsonElement = gson.fromJson(reader, JsonElement.class);
JsonElement metadata = jsonElement.getAsJsonObject().get("__metadata");
if (metadata != null) {
JsonElement etagData = metadata.getAsJsonObject().get("etag");
if (etagData != null)
etag = etagData.getAsString();
}
ODataEntry entry = EntityProvider.readEntry(APPLICATION_JSON, entitySet,
new ByteArrayInputStream(jsonElement.toString().getBytes("UTF-8")),
EntityProviderReadProperties.init().build());
ResultData finalResult = new ResultData();
Map data = getFlattenMapData(entry);
finalResult.setData(data);
finalResult.setEtag(etag);
result.add(finalResult);
}}
} else {
jsonElement = gson.fromJson(reader, JsonElement.class);
JsonElement metadata = jsonElement.getAsJsonObject().get("__metadata");
if (metadata != null) {
JsonElement etagData = metadata.getAsJsonObject().get("etag");
if (etagData != null)
etag = etagData.getAsString();
}
ODataEntry entry = EntityProvider.readEntry(APPLICATION_JSON, entitySet,
new ByteArrayInputStream(jsonElement.toString().getBytes("UTF-8")),
EntityProviderReadProperties.init().build());
ResultData finalResult = new ResultData();
Map data = getFlattenMapData(entry);
finalResult.setData(data);
finalResult.setEtag(etag);
result.add(finalResult);
}
return result;
}
} catch (UnsupportedOperationException | IOException | EntityProviderException e) {
logger.error("Failed in asListOfMapWithEtag method" + e.getMessage(), e);
}finally {
closeInputStream(inputStream);
}
return result;
}
/**
* Converts ODataQueryResult into Map
* It should be used for single entry data
* @return Map
*/
public Map asMap() {
Map jsonMap = null;
ODataEntry entry;
InputStream instream = null;
try {
if(!this.hasResultElement){
instream = stringToInputStream();
if(instream != null) {
entry = EntityProvider.readEntry(APPLICATION_JSON, entitySet, instream,
EntityProviderReadProperties.init().build());
jsonMap = getFlattenMapData(entry);
}
}
else{
logger.info("asMap API will not work as deprecated ODataQueryResult constructor is used");
}
} catch (EntityProviderException | UnsupportedEncodingException e) {
logger.error("Failed to convert response into ODataFeed: " + e.getMessage());
} finally {
closeInputStream(instream);
}
return jsonMap;
}
/**
* Converts ODataQueryResult into List>
* It should be used for collection data
* @return
*/
public List> asListOfMaps() {
List> result = new LinkedList>();
InputStream instream = null;
try {
if(!this.hasResultElement){
instream = stringToInputStream();
if(instream != null) {
ODataFeed feed = EntityProvider.readFeed(APPLICATION_JSON, entitySet, instream,
EntityProviderReadProperties.init().build());
List entries = feed.getEntries();
inlineCount = feed.getFeedMetadata().getInlineCount();
inlineCountAlreadyCalculated = true;
for (ODataEntry entry : entries) {
Map finalResult = getFlattenMapData(entry);
result.add(finalResult);
}
}
}
else{
logger.info("asListOfMaps API will not work as deprecated ODataQueryResult constructor is used");
}
} catch (EntityProviderException | UnsupportedEncodingException e) {
logger.error("Failed to convert response into ODataFeed: " + e.getMessage());
} finally {
closeInputStream(instream);
}
return result;
}
private void closeInputStream(InputStream instream) {
try {
if (instream != null)
instream.close();
} catch (IOException e) {
logger.warn("Unable to safely close the inputstream" + e.getMessage());
}
}
private Map getFlattenMapData(ODataEntry entry) {
Map finalResult = new HashMap<>();
for (Entry property : entry.getProperties().entrySet()) {
if (property.getValue() instanceof ODataFeed) {
ODataFeed feedExpand = (ODataFeed) property.getValue();
List> allChildren = new ArrayList>();
for (ODataEntry feedEntry : feedExpand.getEntries()) {
allChildren.add(getFlattenMapData(feedEntry));
}
finalResult.put(property.getKey(), allChildren);
} else if (property.getValue() instanceof ODataEntry) {
ODataEntry entryFeed = (ODataEntry) property.getValue();
finalResult.put(property.getKey(), getFlattenMapData(entryFeed));
} else {
finalResult.put(property.getKey(), property.getValue());
}
}
return finalResult;
}
/**
* Converts ODataQueryResult into list of POJO
* @param objectType - type of POJO
* @return List - list of POJOs
* @throws IllegalArgumentException
*/
public List asList(final Class objectType) throws IllegalArgumentException {
final List result = Lists.newArrayList();
for (final ResultElement element : getResultElements()) {
if (element.isResultObject()) {
result.add(element.getAsObject().as(objectType));
}
}
return result;
}
/**
* Converts ODataQueryResult into POJO
* @param objectType - type of POJO
* @return T - POJO
*/
public T as(final Class objectType) {
ResultElement resultElnt = null;
try {
if(this.hasResultElement){
resultElnt = this.resultElement;
}
else{
resultElnt = loadEntriesFromResponse();
}
if (resultElnt != null && resultElnt.isResultObject()) {
return resultElnt.getAsObject().as(objectType);
}
} catch (IllegalStateException e) {
logger.debug("Failed to convert httpresponse into ResultElement : " + e.getMessage());
}
return null;
}
/**
* Reads HttpResponse entity data to provide list of ResultElement
* @return List
*/
public Iterable getResultElements() {
final List returnList = Lists.newArrayList();
ResultElement resultElnt = null;
try {
if(this.hasResultElement){
resultElnt = this.resultElement;
}
else{
resultElnt = loadEntriesFromResponse();
}
if (resultElnt != null && resultElnt.isResultCollection()) {
for (final ResultElement recentResultElement : resultElnt.getAsCollection()) {
returnList.add(recentResultElement);
}
}
} catch (IllegalStateException e) {
logger.debug("Failed to convert httpresponse into ResultElement : " + e.getMessage());
}
return returnList;
}
public CollectedResultCollection collect( final String elementName )
{
return new DefaultCollectedResultCollection(elementName, getResultElements());
}
public Optional getIfPresent( final String elementName )
throws IllegalArgumentException
{
final Optional resultElement = getResultElement(elementName);
if( !resultElement.isPresent() ) {
return Optional.absent();
}
return resultElement;
}
@Override
public Iterator iterator() {
return getResultElements().iterator();
}
/**
* Returns inlinecount if present in the response or else return null.
*
* @return inlinecount.
*/
public Integer getInlineCount() {
/*
* There are 2 cases here, 1 is where this method is called before any
* of the as methods are called(asList or asPojo), other case is when
* getInlineCount method is called after one of the as methods are
* called. In the latter case, the inline count is precalculated by the
* particular as method which was called(asListOfMaps or asListOfPojo)
* so we just return this inline count.
*
* In the former case it is not yet calculated, so we can calculate
* inline count by String parsing of the response
*/
if (inlineCountAlreadyCalculated)
return inlineCount;
else
return extractInlineCountFromResponseString();
}
private Integer extractInlineCountFromResponseString() {
String inlineCountRegex = "__count\":\\s*\"(\\d+)\"";
Pattern icpattern = Pattern.compile(inlineCountRegex);
if(this.streamData != null) {
Matcher m = icpattern.matcher(streamData);
if (m.find()) {
return Integer.parseInt(m.group(1));
}
}
return null;
}
public Optional getResultElement( final String elementName )
throws IllegalArgumentException
{
ResultElement resultElement;
try {
resultElement = loadEntriesFromResponse();
if(resultElement != null && resultElement.isResultObject() ) {
return Optional.fromNullable(resultElement.getAsObject().get(elementName));
}
} catch (IllegalStateException e) {
logger.debug("Failed to convert httpresponse into ResultElement : "+e.getMessage());
}
return Optional.absent();
}
}