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

com.sap.cloud.sdk.odatav2.connectivity.cache.metadata.GuavaMetadataCache Maven / Gradle / Ivy

/*******************************************************************************
 * (c) 201X SAP SE or an SAP affiliate company. All rights reserved.
 ******************************************************************************/
package com.sap.cloud.sdk.odatav2.connectivity.cache.metadata;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Callable;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.olingo.odata2.api.edm.Edm;
import org.apache.olingo.odata2.api.edm.EdmException;
import org.apache.olingo.odata2.api.ep.EntityProviderException;
import org.apache.olingo.odata2.client.api.ODataClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.sap.cloud.sdk.cloudplatform.cache.CacheKey;
import com.sap.cloud.sdk.cloudplatform.tenant.TenantAccessor;
import com.sap.cloud.sdk.cloudplatform.tenant.TenantFacade;
import com.sap.cloud.sdk.odatav2.connectivity.ErrorResultHandler;
import com.sap.cloud.sdk.odatav2.connectivity.ODataException;
import com.sap.cloud.sdk.odatav2.connectivity.ODataExceptionType;
import com.sap.cloud.sdk.odatav2.connectivity.internal.ODataConnectivityUtil;

public class GuavaMetadataCache implements MetadataCache{
	private static Logger logger = LoggerFactory.getLogger(GuavaMetadataCache.class);
	private static Cache cache = CacheBuilder.newBuilder().build();
	
	/*
	 * This method gets the metadata from cache if getMetadataCache boolean is set to true.
	 * If getMetadataCache is set to false, then it gets fresh metadata even if the metadata is available in cache.
	 * For both cases,the headers have to be passed.
	 * This method internally updates the cache if metadata is requested from cache and is not available.
	 * The updating of the cache is thread safe. If one thread is accessing the cache, the other thread fails with error 
	 * stating "Metadata currently being loaded. Please try again later".
	 * 
	 */
	public Edm getEdm(final String URL,final HttpClient httpClient,final Map headers, final ErrorResultHandler errorHandler, Boolean getMetadataFromCache) throws ODataException{
		byte[] b=null;
		if(getMetadataFromCache){
			try {
				b = cache.get(URL, new Callable() {

					@Override
					public byte[] call() throws Exception {
						HttpResponse httpResponse = null;
						try {
							HttpGet httpGet = new HttpGet(URL);
							if(headers != null) {
								for(Entry e : headers.entrySet()) {
									httpGet.addHeader(e.getKey(), e.getValue());
								}
							}
							httpResponse = httpClient.execute(httpGet);
							InputStream metadatastream = null;
							ODataConnectivityUtil.checkHttpStatus(httpResponse, errorHandler);
							metadatastream = httpResponse.getEntity().getContent();
							return IOUtils.toByteArray(metadatastream);
							//return ODataClient.newInstance().readMetadata(metadatastream, true).getEdm();
						} catch (Exception e) {
							logger.error("Error occurred during populating metadata : " + e);
							throw e;
						} finally {
							HttpClientUtils.closeQuietly(httpResponse);
						}					
					}
				});

				InputStream is = new ByteArrayInputStream(b);
				return ODataClient.newInstance().readMetadata(is, true).getEdm();

			} catch (Exception e) {
				logger.error("Error occurred while fetching edm from cache " + e);
				throw new ODataException(ODataExceptionType.METADATA_FETCH_FAILED, "Error fetching the metadata", e);
			}
		}else{
			try{
				return getEdm(URL, httpClient, headers, errorHandler);
			}catch(ODataException e){
				logger.error("Error occurred during populating metadata : " + e);
				throw e;
			}catch(Exception e){
				logger.error("Error occurred during populating metadata : " + e);
				throw new ODataException(ODataExceptionType.METADATA_FETCH_FAILED, "Error fetching the metadata", e);
			}
		}
	}
	
	/**
	 * This method gets the metadata from cache if getMetadataCache boolean is set to true.
	 * If getMetadataCache is set to false, then it gets fresh metadata even if the metadata is available in cache.
	 * For both cases,the headers have to be passed.
	 * This method internally updates the cache if metadata is requested from cache and is not available.
	 * The updating of the cache is thread safe. If one thread is accessing the cache, the other thread fails with error 
	 * stating "Metadata currently being loaded. Please try again later".
	 * 
	 */
	public Edm getEdm(final String URL,final HttpClient httpClient,final Map headers, final ErrorResultHandler errorHandler, Boolean 	getMetadataFromCache,final URL metadataFilePath,CacheKey cacheKey,Boolean isCacheRefresh) throws ODataException{
		byte[] b=null;
		
		//If cachekey is null, the defalut tenantIsolation cachekey is generated.
		if(cacheKey == null){
			cacheKey  = getCacheKey(URL);
		}
    else if(cacheKey != null){
      cacheKey.append(URL);   
    }
		
		//If the isCacheRefresh is true , then remove the entry from the cache.
		if(isCacheRefresh){
			removeEntry(cacheKey);
		}

		if(getMetadataFromCache){
			try {
				b = cache.get(cacheKey.toString(), new Callable() {

					@Override
					public byte[] call() throws Exception {
						return cacheEdm(URL,httpClient,headers,errorHandler,metadataFilePath);
					}
				});
				logger.debug("Fetched the metadata from the cache");
				InputStream is = new ByteArrayInputStream(b);
				return ODataClient.newInstance().readMetadata(is, true).getEdm();

			} catch (Exception e) {
				logger.error("Error occurred while fetching edm from cache " , e);
				throw new ODataException(ODataExceptionType.METADATA_FETCH_FAILED, "Error fetching the metadata", e);
			}
		}else{
				if(metadataFilePath != null){
					try(InputStream metadatastream = metadataFilePath.openStream()){
						logger.debug("Fetched the metadata from file.");
						return ODataClient.newInstance().readMetadata(metadatastream, true).getEdm();
					} catch (IOException | EntityProviderException | EdmException e) {
						logger.error("Error occurred while populating metadata : ", e);
						throw new ODataException(ODataExceptionType.METADATA_FETCH_FAILED, "Error fetching the metadata", e);
					} 
				}
				try{
					return getEdm(URL, httpClient, headers, errorHandler);
				
				}catch(ODataException e){
					logger.error("Error occurred while populating metadata: " , e);
					throw e;
				}catch(Exception e){
					logger.error("Error occurred while populating metadata : ", e);
					throw new ODataException(ODataExceptionType.METADATA_FETCH_FAILED, "Error fetching the metadata", e);
				}
		}
	}
	
	/**
	 * This method gets the metadata from cache if getMetadataCache boolean is set to true.
	 * If getMetadataCache is set to false, then it gets fresh metadata even if the metadata is available in cache.
	 * For both cases,the headers have to be passed.
	 * This method internally updates the cache if metadata is requested from cache and is not available.
	 * The updating of the cache is thread safe. If one thread is accessing the cache, the other thread fails with error 
	 * stating "Metadata currently being loaded. Please try again later".
	 * 
	 */
	public Edm getEdm(final String URL,final HttpClient httpClient,final Map headers, final ErrorResultHandler errorHandler, Boolean getMetadataFromCache,final URL metadataFilePath) throws ODataException{
		return getEdm(URL, httpClient, headers, errorHandler, getMetadataFromCache, metadataFilePath,null,null);
	}	
	
	private byte[] cacheEdm(final String URL, final HttpClient httpClient, final Map headers,
			final ErrorResultHandler errorHandler, final URL metadataFilePath) throws ODataException {
		HttpResponse httpResponse = null;

		HttpGet httpGet = new HttpGet(URL);
		if (headers != null) {
			for (Entry e : headers.entrySet()) {
				httpGet.addHeader(e.getKey(), e.getValue());
			}
		}
		// If metadata file present fetch from file else fetch from the service

		if (metadataFilePath != null) {
			try (InputStream metadatastream = metadataFilePath.openStream()) {
				logger.debug("Metadata is not available in the cache. Fetched metadata from file.");
				return IOUtils.toByteArray(metadatastream);
			} catch (IOException e) {
				logger.error("Error occurred while populating metadata : ", e);
				throw new ODataException(ODataExceptionType.METADATA_FETCH_FAILED, "Error fetching the metadata", e);
			}
		} else {
			try{
				httpResponse = httpClient.execute(httpGet);
				ODataConnectivityUtil.checkHttpStatus(httpResponse, errorHandler);
			}catch (Exception e) {
				logger.error("Error occurred while populating metadata : ", e);
				HttpClientUtils.closeQuietly(httpResponse);
				throw new ODataException(ODataExceptionType.METADATA_FETCH_FAILED, "Error fetching the metadata", e);
			}
			
				
				
			try (InputStream metadatastream = httpResponse.getEntity().getContent()) {
				
				logger.debug("Metadata is not available in the cache. Fetched metadata from service.");
				return IOUtils.toByteArray(metadatastream);
				
			} catch (IOException e) {
				logger.error("Error occurred while populating metadata : ", e);
				throw new ODataException(ODataExceptionType.METADATA_FETCH_FAILED, "Error fetching the metadata", e);
				
			}  finally {

				HttpClientUtils.closeQuietly(httpResponse);
			}
		}
	}

	private Edm getEdm(final String URL,final HttpClient httpClient,final Map headers,final ErrorResultHandler errorHandler) throws ClientProtocolException, IOException, ODataException, EdmException, EntityProviderException{
		HttpGet httpGet = new HttpGet(URL);
		if(headers != null) {
			for(Entry e : headers.entrySet()) {
				httpGet.addHeader(e.getKey(), e.getValue());
			}
		}
		HttpResponse httpResponse = null;
		httpResponse = httpClient.execute(httpGet);
		InputStream metadatastream = null;
		ODataConnectivityUtil.checkHttpStatus(httpResponse, errorHandler);
		try {
			metadatastream = httpResponse.getEntity().getContent();
			logger.debug("Fetched metadata from service.");
			return ODataClient.newInstance().readMetadata(metadatastream, true).getEdm();
		} catch (EntityProviderException e) {
			logger.error("Error occurred during populating metadata : " ,e);
			throw e;
		} finally {
			HttpClientUtils.closeQuietly(httpResponse);
		}		
	}

	public void removeEntry(String completeUrl) {
		cache.invalidate(completeUrl);
	}

	/**
	  * Removes the metadata from the cache identified by the cache key.
	  * @param key {@link com.sap.cloud.sdk.cloudplatform.cache.CacheKey Cache key} representing the metadata cache to be removed
	  */
	@Override
	public void removeEntry(CacheKey cacheKey) {
		cache.invalidate(cacheKey);
		
	}
	
	private CacheKey getCacheKey(String metadataUrl) {
		CacheKey cacheKey = null;
		TenantFacade tenantFacade = TenantAccessor.getTenantFacade();
		if (tenantFacade != null && tenantFacade.tryGetCurrentTenant() != null
				&& tenantFacade.tryGetCurrentTenant().isSuccess() && tenantFacade.tryGetCurrentTenant().get() != null) {
			cacheKey = CacheKey.ofTenantIsolation();
		} else {
			cacheKey = CacheKey.ofNoIsolation();
		}
		if(cacheKey != null)
		cacheKey.append(metadataUrl);

		if (logger.isDebugEnabled()) {
			logger.debug("*******CACHE KEY *********** : {} ", cacheKey.toString());
		}
		return cacheKey;
	}
	
	/**
	 * Clears the cache of all content.
	 */
	public void clearCache(){
		cache.invalidateAll();
	}

	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy