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

com.mozu.client.MozuClientImpl Maven / Gradle / Ivy

package com.mozu.client;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpMessage;
import org.apache.http.HttpResponse;
import org.apache.http.RequestLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicHttpEntityEnclosingRequest;
import org.apache.http.util.EntityUtils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mozu.api.ApiContext;
import com.mozu.api.ApiError;
import com.mozu.api.ApiError.Item;
import com.mozu.api.ApiException;
import com.mozu.api.Headers;
import com.mozu.api.MozuClient;
import com.mozu.api.MozuConfig;
import com.mozu.api.MozuUrl;
import com.mozu.api.Version;
import com.mozu.api.cache.CacheManager;
import com.mozu.api.cache.CacheManagerFactory;
import com.mozu.api.cache.impl.CacheItem;
import com.mozu.api.contracts.appdev.AuthTicket;
import com.mozu.api.contracts.tenant.Tenant;
import com.mozu.api.resources.platform.TenantResource;
import com.mozu.api.security.AppAuthenticator;
import com.mozu.api.security.AuthenticationScope;
import com.mozu.api.security.CustomerAuthenticator;
import com.mozu.api.security.UserAuthenticator;
import com.mozu.api.utils.HttpHelper;
import com.mozu.api.utils.JsonUtils;
import com.mozu.api.utils.MozuHttpClientPool;

public class MozuClientImpl implements MozuClient {
    private static final ObjectMapper mapper = JsonUtils.initObjectMapper();

    private ApiContext apiContext = null;
    private String baseAddress = null;
    private CloseableHttpResponse httpResponseMessage = null;
    private String httpContent = null;
    private InputStream streamContent = null;
    private String verb = null;
    private MozuUrl resourceUrl = null;
    private HashMap headers = new HashMap();
    private final Class responseType;
    private CacheItem cacheItem = null;
    private String cacheKey = null;
    
    public MozuClientImpl() {
        this.responseType = null;
    }

    public MozuClientImpl(Class responseType) throws Exception {
        this.responseType = responseType;
    }

    public void setContext(ApiContext apiContext) {
        this.apiContext = apiContext;

        if (apiContext != null) {
            if (apiContext.getTenantId() > 0) {
                addHeader(Headers.X_VOL_TENANT, String.valueOf(apiContext.getTenantId()));
            }
    
            if (apiContext.getSiteId() != null && apiContext.getSiteId() > 0) {
                addHeader(Headers.X_VOL_SITE, String.valueOf(apiContext.getSiteId()));
            }
    
            if (apiContext.getMasterCatalogId() != null && apiContext.getMasterCatalogId() > 0) {
                addHeader(Headers.X_VOL_MASTER_CATALOG, String.valueOf(apiContext.getMasterCatalogId()));
            }
    
            if (apiContext.getCatalogId() != null && apiContext.getCatalogId() > 0) {
                addHeader(Headers.X_VOL_CATALOG, String.valueOf(apiContext.getCatalogId()));
            }
            
            if (apiContext.getLocale() != null) {
                addHeader(Headers.X_VOL_LOCALE, String.valueOf(apiContext.getLocale()));
            }
 
            if (apiContext.getCurrency() != null) {
                addHeader(Headers.X_VOL_CURRENCY, String.valueOf(apiContext.getCurrency()));
            }
            
            if (apiContext.getCustomHeaders() != null) {
                for (Map.Entry headerEntry : apiContext.getCustomHeaders().entrySet()) {
                    addHeader(headerEntry.getKey(), headerEntry.getValue());
                }
            }
        }
    }

    public void setBaseAddress(String baseAddress) {
        this.baseAddress = baseAddress;
    }

    public void addHeader(String header, String value) {
        headers.put(header, value);
    }

    public void setVerb(String verb) {
        this.verb = verb;
    }

    public void setResourceUrl(MozuUrl resourceUrl) {
        this.resourceUrl = resourceUrl;
    }

    public  void setBody(TBody body) throws JsonProcessingException {
        httpContent = mapper.writeValueAsString(body);
    }

    public void setBody(InputStream body) throws JsonProcessingException {
        streamContent = body;
    }

    public void setBody(String body) {
        httpContent = body;
    }

    public String getStringResult() throws Exception {
        return stringContent();
    }

    @SuppressWarnings("unchecked")
    public TResult getResult() throws Exception {
        TResult tResult = null;
        try {
        	if (httpResponseMessage.getStatusLine().getStatusCode() == 404)
        		return null;

            if (responseType != null) {
                String className = responseType.getName();
                if (className.equals(java.io.InputStream.class.getName())) {
                    tResult = (TResult) httpResponseMessage.getEntity().getContent();
                } else {
                	
                	
                	if (cacheItem != null)
                		tResult = deserialize(cacheItem.getContent(), responseType);
                	else
                		tResult = deserialize(getStringResult(), responseType);
                }
            }
        } finally {
            EntityUtils.consume(httpResponseMessage.getEntity());
            httpResponseMessage.close();
        }
        return tResult;
    }

    protected void validateContext() throws Exception {
    	AppAuthenticator appAuthenticator = AppAuthenticator.getInstance();
        if (appAuthenticator == null) {
           throw new ApiException("Application has not been authorized to access Mozu.");
        } 
        if (resourceUrl.getLocation() == MozuUrl.UrlLocation.TENANT_POD) {
            if (apiContext == null || apiContext.getTenantId() <= 0)
                throw new ApiException("TenantId is missing");

            if (StringUtils.isBlank(apiContext.getTenantUrl())) {
                TenantResource tenantResource = new TenantResource();
                Tenant tenant = tenantResource.getTenant(apiContext.getTenantId());

                if (tenant == null)
                    throw new ApiException("Tenant " + apiContext.getTenantId() + " Not found");
                baseAddress = HttpHelper.getUrl(tenant.getDomain());
            } else {
                baseAddress = apiContext.getTenantUrl();
            }
        }else if (resourceUrl.getLocation() == MozuUrl.UrlLocation.HOME_POD){
        	if (StringUtils.isBlank(MozuConfig.getBaseUrl())) {
                throw new ApiException("Authentication.Instance.BaseUrl is missing");
             }

            baseAddress = MozuConfig.getBaseUrl();
         }else if(resourceUrl.getLocation() == MozuUrl.UrlLocation.PCI_POD){
        	if(apiContext == null ||apiContext.getTenantId() < 0){
        		 throw new ApiException("TenantId is missing");
        	}
        	if (StringUtils.isBlank(MozuConfig.getBasePciUrl())) {
                throw new ApiException("Authentication.Instance.BasePciUrl is missing");
             }
        	Tenant tenant=getTenant(apiContext.getTenantId());
        	baseAddress = tenant.getIsDevTenant()?MozuConfig.getBaseDevPciUrl():MozuConfig.getBasePciUrl();
        }
    }
    
    private Tenant getTenant(Integer tenantId) throws Exception{
    	 TenantResource tenantResource = new TenantResource();
         Tenant tenant = tenantResource.getTenant(tenantId);
         if (tenant == null)
             throw new ApiException("Tenant " + tenantId + " Not found");
		return tenant;
    }

    @SuppressWarnings("unchecked")
    public void executeRequest() throws Exception {
        validateContext();

        CloseableHttpClient client = MozuHttpClientPool.getInstance().getHttpClient();
        BasicHttpEntityEnclosingRequest request = buildRequest();
        URL url = new URL(baseAddress);
        String hostNm = url.getHost();
        int port = url.getPort();
        String sche = url.getProtocol();
        HttpHost httpHost = new HttpHost(hostNm, port, sche);

        setCacheKey(request);
        CacheManager cache = (CacheManager) CacheManagerFactory.getCacheManager();
        if (cache != null) {
        	cacheItem = cache.get(cacheKey);
        	if (cacheItem != null)
                request.addHeader("If-None-Match", cacheItem.geteTag());
        }
        httpResponseMessage = client.execute(httpHost, request);
        try {
            ensureSuccess(httpResponseMessage, request.getRequestLine());
            setCache();
        } catch (Exception e) {
            // make sure on exception that that response is closed
            EntityUtils.consume(httpResponseMessage.getEntity());
            httpResponseMessage.close();
            throw e;
        }
    }

    public TResult executePostRequest(Object bodyObject, String resourceUrl, Map headers) {
        return this.executeRequest(bodyObject, new HttpPost(resourceUrl), headers);
    }
    
    public TResult executePutRequest(Object bodyObject, String resourceUrl, Map headers) {
        return this.executeRequest(bodyObject, new HttpPut(resourceUrl), headers);
    }
    
    public void executeDeleteRequest(String resourceUrl, Map headers) throws ApiException {

        HttpDelete delete = new HttpDelete(resourceUrl);
        delete.setHeader("Accept", "application/json");
        delete.setHeader("Content-type", "application/json");
        if (headers!=null) {
            for (Map.Entry entry: headers.entrySet()) {
                delete.addHeader(entry.getKey(), entry.getValue());
            }
        }
        try {
            executeRequest(delete);
        } catch (Exception ioe) {
            throw new ApiException("Exception occurred while authenticating user: "
                    + ioe.getMessage());
        }
    }
    
    private void executeRequest(HttpRequestBase request) throws Exception {

        CloseableHttpClient client = MozuHttpClientPool.getInstance().getHttpClient();

        httpResponseMessage = client.execute(request);
        try {
            ensureSuccess(httpResponseMessage, request.getRequestLine());
        } catch (Exception e) {
            // make sure on exception that that response is closed
            EntityUtils.consume(httpResponseMessage.getEntity());
            httpResponseMessage.close();
            throw e;
        }
    }

    private TResult executeRequest(Object bodyObject, HttpEntityEnclosingRequestBase request, Map headers) {
        TResult result = null;

        try {
            String body = mapper.writeValueAsString(bodyObject);
            StringEntity se = new StringEntity(body);
            request.setEntity(se);
            request.setHeader("Accept", "application/json");
            request.setHeader("Content-type", "application/json");
            if (headers!=null) {
                for (Map.Entry entry: headers.entrySet()) {
                    request.addHeader(entry.getKey(), entry.getValue());
                }
            }
        } catch (UnsupportedEncodingException uee) {
            throw new ApiException("JSON error proccessing authentication: " + uee.getMessage());
        } catch (JsonProcessingException jpe) {
            throw new ApiException("JSON error proccessing authentication: " + jpe.getMessage());
        }

        try {
            executeRequest(request);
            result = getResult();
        } catch (ApiException ae) {
            throw ae;
        } catch (Exception ioe) {
            throw new ApiException("Exception occurred while authenticating application: "
                    + ioe.getMessage());
        }

        return result;
    }

    public void cleanupHttpConnection () throws Exception {
        if (httpResponseMessage != null) {
            EntityUtils.consume(httpResponseMessage.getEntity());
            httpResponseMessage.close();
        }
    }

    
    
    private void setCacheKey(BasicHttpEntityEnclosingRequest request) {
    	StringBuilder key = new StringBuilder();
    	key.append(request.getRequestLine().getUri().toString());
         if (apiContext != null) {
        	 if (apiContext.getSiteId() != null)
        		 key.append(apiContext.getSiteId());

        	 if (!StringUtils.isEmpty(apiContext.getCurrency()))
        		 key.append(apiContext.getCurrency());
        	 if (!StringUtils.isEmpty(apiContext.getLocale()))
        		 key.append(apiContext.getLocale());
        	 if (apiContext.getMasterCatalogId() != null)
        		 key.append(apiContext.getMasterCatalogId());
        	 if (apiContext.getCatalogId() != null)
        		 key.append(apiContext.getCatalogId());
        	 
         	String dataViewMode = getHeaderValue(Headers.X_VOL_DATAVIEW_MODE, request);
         	if (!StringUtils.isEmpty(dataViewMode))
         		key.append(dataViewMode);
         }
         cacheKey =  key.toString();
    }
    
    @SuppressWarnings("unchecked")
    private void setCache() throws Exception {
        String eTag = getHeaderValue("ETag", httpResponseMessage);
        if (cacheItem != null && httpResponseMessage.getStatusLine().getStatusCode() == 304)
        {
            //Do nothing
            //httpResponseMessage = (CloseableHttpResponse) cacheItem.getItem();
        }
        else if (StringUtils.isNotEmpty(eTag) && httpResponseMessage.getStatusLine().getStatusCode() != 404)
        {
            com.mozu.api.cache.CacheManager cache = (com.mozu.api.cache.CacheManager) com.mozu.api.cache.CacheManagerFactory.getCacheManager();
            if (cache != null) {
                cacheItem = new CacheItem();
                cacheItem.seteTag(eTag);
                cacheItem.setKey(cacheKey);
                cacheItem.setContent(stringContent());
                
                cache.put(cacheKey, cacheItem);
            }
        }
    }
    
    private TResult deserialize(String jsonString, Class cls) throws Exception {
        return mapper.readValue(jsonString, cls);
    }

    private String stringContent() throws Exception {
        HttpEntity httpEntity = httpResponseMessage.getEntity();
        InputStream stream = (InputStream) httpEntity.getContent();
        return org.apache.commons.io.IOUtils.toString(stream, "UTF-8");
    }

    private BasicHttpEntityEnclosingRequest buildRequest() throws Exception {
        String url = baseAddress + resourceUrl.getUrl();
        BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest(verb, url);

        if (verb.equals("POST") || verb.equals("PUT")) {
            if (StringUtils.isNotBlank(httpContent)) {
                request.setHeader("Accept", "application/json");
                StringEntity entity = new StringEntity(httpContent, Consts.UTF_8);
                request.setEntity(entity);
            } else if (this.streamContent != null) {
                long length = -1;
                if (streamContent instanceof FileInputStream) {
                    if (((FileInputStream)streamContent).getChannel() != null) {
                        length = ((FileInputStream)streamContent).getChannel().size();
                    }
                } else {
                    throw new UnsupportedOperationException ("The InputStream is not supported. It must be an instance of FileInputStream.");
                }
                InputStreamEntity entity = new InputStreamEntity(this.streamContent, length);
                request.setEntity(entity); 
            }
        }

        if (!headers.containsKey(Headers.CONTENT_TYPE)) {
            request.setHeader("Content-type", "application/json; charset=utf-8");
        }
        if (apiContext != null && apiContext.getUserAuthTicket() != null) {
            setUserClaims();
        }

        Iterator> i = headers.entrySet().iterator();
        while (i.hasNext()) {
            Entry header = i.next();
            request.addHeader(header.getKey(), header.getValue());
        }

        request.addHeader(Headers.X_VOL_APP_CLAIMS, AppAuthenticator.addAuthHeader());
        request.addHeader(Headers.X_VOL_VERSION, Version.API_VERSION);

        
        
        return request;
    }

    private void setUserClaims() {
        AuthTicket newAuthTicket = null;
        if (apiContext.getUserAuthTicket().getScope() == AuthenticationScope.Customer)
            newAuthTicket = CustomerAuthenticator.ensureAuthTicket(apiContext.getUserAuthTicket(), apiContext.getTenantId(), apiContext.getSiteId());
        else
            newAuthTicket = UserAuthenticator.ensureAuthTicket(apiContext.getUserAuthTicket());
        if (newAuthTicket != null) {
            apiContext.getUserAuthTicket().setAccessToken(newAuthTicket.getAccessToken());
            apiContext.getUserAuthTicket().setAccessTokenExpiration(
                    newAuthTicket.getAccessTokenExpiration());
        }

        addHeader(Headers.X_VOL_USER_CLAIMS, apiContext.getUserAuthTicket().getAccessToken());
    }

    protected Map getHeaders() {
        return headers;
    }

    protected void ensureSuccess(HttpResponse response, RequestLine requestLine ) throws ApiException {
        int statusCode = response.getStatusLine().getStatusCode();
        String correlationId = getHeaderValue(Headers.X_VOL_CORRELATION, response);
        if (statusCode == 304 || statusCode >= 200 && statusCode <= 300) return;
        
        
    	ApiError apiError = new ApiError();
    	apiError.setCorrelationId(correlationId);
    	
    	if (statusCode == 404 && StringUtils.isEmpty(correlationId))
    		apiError.setMessage(requestLine.getUri().toString() +" not found");
    	else if (!StringUtils.isEmpty(correlationId)) {
    		try {
    			apiError = mapper.readValue(stringContent(), ApiError.class);
    			apiError.setCorrelationId(correlationId);
    			if (apiError.getErrorCode().equals("ITEM_NOT_FOUND") && statusCode == 404  && StringUtils.endsWithIgnoreCase("get",requestLine.getMethod())) return;
    		} catch (JsonProcessingException jpe) {
                throw new ApiException("An error has occurred. Status Code: " + statusCode   
                        + " Status Message: " + response.getStatusLine().getReasonPhrase(), statusCode);
            } catch (IOException ioe) {
                throw new ApiException("An error occurred. Status Code: " + statusCode   
                        + " Status Message: " + response.getStatusLine().getReasonPhrase(), statusCode);
            } catch (Exception e) {
				// TODO Auto-generated catch block
            	throw new ApiException("An error occurred. Status Code: " + statusCode   
                        + " Status Message: " + response.getStatusLine().getReasonPhrase(), statusCode);
			}
    	} else
    		apiError.setMessage("Unknown Error");
        throw new ApiException(getMozuErrorMessage(apiError), apiError, statusCode);
    }
    
    private static String getMozuErrorMessage(ApiError apiError) {
        StringBuilder errorMessage = new StringBuilder("Error returned from Mozu. Correlation ID: ");
        
        errorMessage.append(apiError.getCorrelationId());
        errorMessage.append(".  Message: ");
        
        if (StringUtils.isNotBlank(apiError.getMessage())) {
            errorMessage.append(apiError.getMessage());
        } else if (apiError.getExceptionDetail() != null && StringUtils.isNotBlank(apiError.getExceptionDetail().getMessage())) {
            errorMessage.append(apiError.getExceptionDetail().getMessage());
        } else if (apiError.getItems().size() > 0) {
            for (Item item : apiError.getItems()) {
                errorMessage.append(item.getMessage());
                errorMessage.append(". Error Code: ").append(item.getErrorCode());
            }
        } else {
            errorMessage.append("No error message returned from Mozu.");
        }
        
        return errorMessage.toString();
    }
  
    private String getHeaderValue(String header, HttpMessage httpMessage) {
      if (httpMessage.containsHeader(header))
          return (httpMessage.getFirstHeader(header)).getValue();
      else
          return null;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy