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

com.paypal.base.rest.PayPalResource Maven / Gradle / Ivy

There is a newer version: 1.14.0
Show newest version
package com.paypal.base.rest;

import com.paypal.base.*;
import com.paypal.base.exception.BaseException;
import com.paypal.base.exception.ClientActionRequiredException;
import com.paypal.base.exception.HttpErrorException;
import com.paypal.base.sdk.info.SDKVersionImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * PayPalResource acts as a base class for REST enabled resources.
 */
public abstract class PayPalResource extends PayPalModel{

	private static final Logger log = LoggerFactory.getLogger(PayPalResource.class);
	
	/*
	 * The class relies on an implementation of APICallPreHandler (here
	 * RESTAPICallPreHandler)to get access to endpoint, HTTP headers, and
	 * payload.
	 */
	/**
	 * Map used in dynamic configuration
	 */
	private static Map configurationMap;

	/**
	 * Configuration enabled flag
	 */
	private static boolean configInitialized = false;

	/**
	 * Last request sent to Service
	 */
	private static final ThreadLocal LASTREQUEST = new ThreadLocal();

	/**
	 * Last response returned form Service
	 */
	private static final ThreadLocal LASTRESPONSE = new ThreadLocal();

	/**
	 * Initialize the system using a File(Properties file). The system is
	 * initialized using the given file and if the initialization succeeds the
	 * default 'sdk_config.properties' can only be loaded by calling the method
	 * initializeToDefault()
	 * 
	 * @param file
	 *            File object of a properties entity
	 * @throws PayPalRESTException
	 * @return	OAuthTokenCredential instance with client ID and client secret stored in configuration file.
	 */
	public static OAuthTokenCredential initConfig(File file) throws PayPalRESTException {
		try {
			if (!file.exists()) {
				throw new FileNotFoundException("File doesn't exist: "
						+ file.getAbsolutePath());
			}
			FileInputStream fis = new FileInputStream(file);
			return initConfig(fis);
		} catch (IOException ioe) {
			log.error(ioe.getMessage(), ioe);
			throw new PayPalRESTException(ioe.getMessage(), ioe);
		}

	}

	/**
	 * Initialize using Properties. The system is initialized using the given
	 * properties object and if the initialization succeeds the default
	 * 'sdk_config.properties' can only be loaded by calling the method
	 * initializeToDefault()
	 * 
	 * @param properties
	 *            Properties object
	 * @return	OAuthTokenCredential instance with client ID and client secret in given properties.
	 */
	public static OAuthTokenCredential initConfig(Properties properties) {
		configurationMap = SDKUtil.constructMap(properties);
		configInitialized = true;
		return getOAuthTokenCredential();
	}

	/**
	 * Initialize using {@link InputStream}(of a Properties file).. The system
	 * is initialized using the given {@link InputStream} and if the
	 * initialization succeeds the default 'sdk_config.properties' can only be
	 * loaded by calling the method initializeToDefault(). The system is
	 * initialized with the information after loading defaults for the
	 * parameters that are not passed as part of the configuration. For defaults
	 * see {@link ConfigManager}
	 * 
	 * @param inputStream
	 *            InputStream
	 * @throws PayPalRESTException
	 * @return	OAuthTokenCredential instance with client ID and client secret stored in given inputStream.
	 */
	public static OAuthTokenCredential initConfig(InputStream inputStream)
			throws PayPalRESTException {
		try {
			Properties properties = new Properties();
			properties.load(inputStream);

			/*
			 * Create a Map instance and combine it with default values
			 */
			configurationMap = SDKUtil.constructMap(properties);
			configInitialized = true;
			return getOAuthTokenCredential();
		} catch (IOException ioe) {
			log.error(ioe.getMessage(), ioe);
			throw new PayPalRESTException(ioe.getMessage(), ioe);
		}
	}
	
	/**
	 * Return Client ID from configuration Map
	 */
	public static String getClientID() {
		return configurationMap.get(Constants.CLIENT_ID);
	}

	/**
	 * Returns Client Secret from configuration Map
	 */
	public static String getClientSecret() {
		return configurationMap.get(Constants.CLIENT_SECRET);
	}
	
	/**
	 * Returns OAuthTokenCredential instance using client ID and client secret loaded from configuration.
	 * @return OAuthTokenCredential instance.
	 */
	public static OAuthTokenCredential getOAuthTokenCredential() {
		if(configInitialized){
			return new OAuthTokenCredential(getClientID(), getClientSecret(), configurationMap);
		}else{
			return new OAuthTokenCredential(getClientID(), getClientSecret());			
		}
	}

	/**
	 * Initialize to default properties
	 * 
	 * @throws PayPalRESTException
	 */
	public static void initializeToDefault() throws PayPalRESTException {
		configurationMap = SDKUtil.combineDefaultMap(ConfigManager
				.getInstance().getConfigurationMap());
	}

	/**
	 * Returns the last request sent to the Service
	 * 
	 * @return Last request sent to the server
	 */
	public static String getLastRequest() {
		return LASTREQUEST.get();
	}

	/**
	 * Returns the last response returned by the Service
	 * 
	 * @return Last response got from the Service
	 */
	public static String getLastResponse() {
		return LASTRESPONSE.get();
	}
	
	public static Map getConfigurations() {
		return configurationMap;
	}

	/**
	 * Configures and executes REST call: Supports JSON
	 * 
	 * @deprecated Please use {@link #configureAndExecute(APIContext, HttpMethod, String, String, Class)} instead.
	 * Passing APIContext gives us better information than just raw access token.
	 *
	 * @param 
	 *            Response Type for de-serialization
	 * @param accessToken
	 *            OAuth AccessToken to be used for the call.
	 * @param httpMethod
	 *            Http Method verb
	 * @param resourcePath
	 *            Resource URI path
	 * @param payLoad
	 *            Payload to Service
	 * @param clazz
	 *            {@link Class} object used in De-serialization
	 * @return T
	 * @throws PayPalRESTException
	 */
	public static  T configureAndExecute(String accessToken,
			HttpMethod httpMethod, String resourcePath, String payLoad,
			Class clazz) throws PayPalRESTException {
		return configureAndExecute(new APIContext(accessToken), httpMethod, resourcePath, payLoad, clazz);
	}

	/**
	 * Configures and executes REST call
	 *
	 * @param 
	 *            Response Type for de-serialization
	 * @param apiContext
	 *            {@link APIContext} to be used for the call.
	 * @param httpMethod
	 *            Http Method verb
	 * @param resourcePath
	 *            Resource URI path
	 * @param payLoad
	 *            Payload to Service
	 * @param clazz
	 *            {@link Class} object used in De-serialization
	 * @return T
	 * @throws PayPalRESTException
	 */
	public static  T configureAndExecute(APIContext apiContext,
			HttpMethod httpMethod, String resourcePath, String payLoad,
			Class clazz) throws PayPalRESTException {
		return configureAndExecute(apiContext, httpMethod, resourcePath, payLoad, clazz, null);
	}

	/**
	 * Configures and executes REST call: Supports JSON
	 * 
	 * @param 
	 *            Response Type for de-serialization
	 * @param apiContext
	 *            {@link APIContext} to be used for the call.
	 * @param httpMethod
	 *            Http Method verb
	 * @param resourcePath
	 *            Resource URI path
	 * @param payLoad
	 *            Payload to Service
	 * @param clazz
	 *            {@link Class} object used in De-serialization
	 * @param accessToken
	 * 			  Access Token to be used instead of apiContext
	 * @return T
	 * @throws PayPalRESTException
	 */
	public static  T configureAndExecute(APIContext apiContext,
			HttpMethod httpMethod, String resourcePath, String payLoad,
			Class clazz, String accessToken) throws PayPalRESTException {
		T t = null;
		Map cMap;
		String requestId;
		Map headersMap;
		if (apiContext != null) {
			if (apiContext.getHTTPHeader(Constants.HTTP_CONTENT_TYPE_HEADER) == null) {
				apiContext.addHTTPHeader(Constants.HTTP_CONTENT_TYPE_HEADER, Constants.HTTP_CONTENT_TYPE_JSON);
			}
			if (apiContext.getSdkVersion() != null) {
				apiContext.setSdkVersion(new SDKVersionImpl());
			}

			if (apiContext.getConfigurationMap() != null) {
				cMap = SDKUtil.combineDefaultMap(apiContext
						.getConfigurationMap());
			} else {
				if (!configInitialized) {
					initializeToDefault();
				}

				/*
				 * The Map returned here is already combined with default values
				 */
				cMap = new HashMap(
						configurationMap);
			}
			headersMap = apiContext.getHTTPHeaders();
			if (accessToken == null) {
				accessToken = apiContext.fetchAccessToken();
			}
			// If it is still null, throw the exception.
			if (accessToken == null) {
				throw new IllegalArgumentException("AccessToken cannot be null or empty");
			}
			requestId = apiContext.getRequestId();

			APICallPreHandler apiCallPreHandler = createAPICallPreHandler(cMap,
					payLoad, resourcePath, headersMap, accessToken, requestId,
					apiContext.getSdkVersion());
			HttpConfiguration httpConfiguration = createHttpConfiguration(cMap,
					httpMethod, apiCallPreHandler);
			t = execute(apiCallPreHandler, httpConfiguration, clazz);
		}
		return t;
	}

	/**
	 * Configures and executes REST call: Supports JSON
	 *
	 * @deprecated Please use {@link #configureAndExecute(APIContext, HttpMethod, String, String, Class)} instead. Headers could be passed directly
	 * to #APIContext itself.
	 *
	 * @param 
	 * @param apiContext
	 *            {@link APIContext} to be used for the call.
	 * @param httpMethod
	 *            Http Method verb
	 * @param resourcePath
	 *            Resource URI path
	 * @param headersMap
	 *            Optional headers Map
	 * @param payLoad
	 *            Payload to Service
	 * @param clazz
	 *            {@link Class} object used in De-serialization
	 * @return T
	 * @throws PayPalRESTException
	 */
	public static  T configureAndExecute(APIContext apiContext,
			HttpMethod httpMethod, String resourcePath,
			Map headersMap, String payLoad, Class clazz)
			throws PayPalRESTException {
		if (apiContext != null) {
			apiContext.addHTTPHeaders(headersMap);
		}
		return configureAndExecute(apiContext, httpMethod, resourcePath, payLoad, clazz);
	}

	/**
	 * Returns a implementation of {@link APICallPreHandler} for the underlying
	 * layer.
	 * 
	 * @param configurationMap
	 *            configuration Map
	 * @param payLoad
	 *            Raw payload
	 * @param resourcePath
	 *            URI part of the resource operated on
	 * @param headersMap
	 *            Custom HTTP headers map
	 * @param accessToken
	 *            OAuth Token
	 * @param requestId
	 *            PayPal Request Id
	 * @param sdkVersion
	 *            {@link SDKVersion} instance
	 * @return APICallPreHandler
	 */
	public static APICallPreHandler createAPICallPreHandler(
			Map configurationMap, String payLoad,
			String resourcePath, Map headersMap,
			String accessToken, String requestId, SDKVersion sdkVersion) {
		APICallPreHandler apiCallPreHandler = null;
		RESTAPICallPreHandler restAPICallPreHandler = new RESTAPICallPreHandler(
				configurationMap, headersMap);
		restAPICallPreHandler.setResourcePath(resourcePath);
		restAPICallPreHandler.setRequestId(requestId);
		restAPICallPreHandler.setAuthorizationToken(accessToken);
		restAPICallPreHandler.setPayLoad(payLoad);
		restAPICallPreHandler.setSdkVersion(sdkVersion);
		apiCallPreHandler = restAPICallPreHandler;
		return apiCallPreHandler;
	}

	/**
	 * Execute the API call and return response
	 * 
	 * @param 
	 *            Generic Type for response object construction
	 * @param apiCallPreHandler
	 *            Implementation of {@link APICallPreHandler}
	 * @param httpConfiguration
	 *            {@link HttpConfiguration}
	 * @param clazz
	 *            Response Object class
	 * @return Response Type
	 * @throws PayPalRESTException
	 */
	private static  T execute(APICallPreHandler apiCallPreHandler,
			HttpConfiguration httpConfiguration, Class clazz)
			throws PayPalRESTException {
		T t = null;
		ConnectionManager connectionManager;
		HttpConnection httpConnection;
		Map headers;
		String responseString;
		try {

			// REST Headers
			headers = apiCallPreHandler.getHeaderMap();

			// HttpConnection Initialization
			connectionManager = ConnectionManager.getInstance();
			httpConnection = connectionManager.getConnection(httpConfiguration);
			httpConnection.createAndconfigureHttpConnection(httpConfiguration);
			
			// capture request and log if conditions are met
			LASTREQUEST.set(apiCallPreHandler.getPayLoad());
			String mode = "";
			if (configurationMap != null) {
				mode = configurationMap.get(Constants.MODE);
			} else if (apiCallPreHandler.getConfigurationMap() != null) {
				mode = apiCallPreHandler.getConfigurationMap().get(Constants.MODE);
			}
			if (Constants.LIVE.equalsIgnoreCase(mode) && log.isDebugEnabled()) {
				log.warn("Log level cannot be set to DEBUG in " + Constants.LIVE + " mode. Skipping request/response logging...");
			} 
			if (!Constants.LIVE.equalsIgnoreCase(mode)) {
				log.debug("request header: " + headers.toString());
				log.debug("request body: " + LASTREQUEST.get());
			}
			
			// send request and receive response
			responseString = httpConnection.execute(null,
					apiCallPreHandler.getPayLoad(), headers);
			
			// capture response and log if conditions are met
			LASTRESPONSE.set(responseString);
			if (!Constants.LIVE.equalsIgnoreCase(mode)) {
				log.debug("response: " + LASTRESPONSE.get());
			}
			if (clazz != null) {
				t = JSONFormatter.fromJSON(responseString, clazz);
			}
		} catch (ClientActionRequiredException e) {
			throw PayPalRESTException.createFromHttpErrorException(e);
		} catch (HttpErrorException e) {
			throw PayPalRESTException.createFromHttpErrorException(e);
		} catch (Exception e) {
			throw new PayPalRESTException(e.getMessage(), e);
		}
		return t;
	}

	/**
	 * Utility method that creates a {@link HttpConfiguration} object from the
	 * passed information
	 * 
	 * @param configurationMap
	 *            Configuration to base the construction upon.
	 * @param httpMethod
	 *            HTTP Method
	 * @param apiCallPreHandler
	 *            {@link APICallPreHandler} for retrieving EndPoint
	 * @return
	 * @throws BaseException 
	 * @throws PayPalRESTException 
	 */
	private static HttpConfiguration createHttpConfiguration(
			Map configurationMap, HttpMethod httpMethod,
			APICallPreHandler apiCallPreHandler) throws PayPalRESTException {
		HttpConfiguration httpConfiguration = new HttpConfiguration();
		httpConfiguration.setHttpMethod(httpMethod.toString());
		String endpoint = apiCallPreHandler.getEndPoint();
		if (endpoint == null || endpoint.isEmpty()) {
			throw new PayPalRESTException("The endpoint could not be fetched properly. You may be missing `mode` in your configuration.");
		}
		httpConfiguration.setEndPointUrl(apiCallPreHandler.getEndPoint());
		httpConfiguration
				.setGoogleAppEngine(Boolean.parseBoolean(configurationMap
						.get(Constants.GOOGLE_APP_ENGINE)));
		if (Boolean.parseBoolean(configurationMap
				.get((Constants.USE_HTTP_PROXY)))) {
			httpConfiguration.setProxyPort(Integer.parseInt(configurationMap
					.get((Constants.HTTP_PROXY_PORT))));
			httpConfiguration.setProxyHost(configurationMap
					.get((Constants.HTTP_PROXY_HOST)));
			httpConfiguration.setProxyUserName(configurationMap
					.get((Constants.HTTP_PROXY_USERNAME)));
			httpConfiguration.setProxyPassword(configurationMap
					.get((Constants.HTTP_PROXY_PASSWORD)));
		}
		httpConfiguration.setConnectionTimeout(Integer
				.parseInt(configurationMap
						.get(Constants.HTTP_CONNECTION_TIMEOUT)));
		httpConfiguration.setMaxRetry(Integer.parseInt(configurationMap
				.get(Constants.HTTP_CONNECTION_RETRY)));
		httpConfiguration.setReadTimeout(Integer.parseInt(configurationMap
				.get(Constants.HTTP_CONNECTION_READ_TIMEOUT)));
		httpConfiguration.setMaxHttpConnection(Integer
				.parseInt(configurationMap
						.get(Constants.HTTP_CONNECTION_MAX_CONNECTION)));
		httpConfiguration.setIpAddress(configurationMap
				.get(Constants.DEVICE_IP_ADDRESS));
		return httpConfiguration;
	}

	/**
	 * Returns ClientCredentials with client id and client secret from configuration Map
	 *
	 * @return Client credentials
     */
	public static ClientCredentials getCredential() {
		ClientCredentials credentials = new ClientCredentials();
		Properties configFileProperties = getConfigFileProperties();
		addConfigurations(configFileProperties);
		credentials.setClientID(configurationMap.get(Constants.CLIENT_ID));
		credentials.setClientSecret(configurationMap.get(Constants.CLIENT_SECRET));
		return credentials;
	}

	/**
	 * @deprecated Please use static method `getCredential` instead.
	 *
	 * Returns ClientCredentials with client id and client secret from configuration Map.
	 *
	 * @return Client credentials
	 */
	public ClientCredentials getClientCredential() {
		return PayPalResource.getCredential();
	}
	
	/**
	 * Fetches the properties from default configuration file.
	 * 
	 * @return {@link Properties}
	 */
	private static Properties getConfigFileProperties() {
		Properties properties = new Properties();
		try {
			properties.load(new FileReader(
					new File(PayPalResource.class.getClassLoader().getResource(Constants.DEFAULT_CONFIGURATION_FILE).getFile())));
		} catch (FileNotFoundException e) {
			return null;
		} catch (IOException e) {
			return null;
		}
		return properties;
	}

	/**
	 * Merges properties object with the configuration hash map. The configuration values are given higher priority.
	 * 
	 * @param properties
	 */
	private static void addConfigurations(Properties properties) {
		if (configurationMap == null) {
			configurationMap = new HashMap();
		}
		if (properties != null) {
			for (final String name : properties.stringPropertyNames()) {
				if (!configurationMap.containsKey(name)) {
					configurationMap.put(name, properties.getProperty(name));
				}
			}	
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy