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

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(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy