/** * \package com.bluevia.android.payment.client This package contains the clients of Bluevia Payment Service */ package com.bluevia.android.payment.client; import java.io.IOException; import java.text.Format; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import oauth.signpost.OAuthProviderListener; import oauth.signpost.http.HttpRequest; import oauth.signpost.http.HttpResponse; import com.bluevia.android.commons.Encoding; import com.bluevia.android.commons.Entity; import com.bluevia.android.commons.GsdpConstants; import com.bluevia.android.commons.connector.http.oauth.BVAuthorizationHeaderSigningStrategy; import com.bluevia.android.commons.connector.http.oauth.IOAuth; import com.bluevia.android.commons.connector.http.oauth.OAuthToken; import com.bluevia.android.commons.connector.http.oauth.RequestToken; import com.bluevia.android.commons.data.xmlrpc.MethodCall; import com.bluevia.android.commons.data.xmlrpc.MethodResponse; import com.bluevia.android.commons.exception.BlueviaException; import com.bluevia.android.commons.parser.xml.XmlConstants; import com.bluevia.android.oauth.client.BVOauthClient; import com.bluevia.android.payment.data.GetPaymentStatusParams; import com.bluevia.android.payment.data.MakePaymentParams; import com.bluevia.android.payment.data.PaymentInfo; import com.bluevia.android.payment.data.PaymentRequestTokenParams; import com.bluevia.android.payment.data.PaymentResult; import com.bluevia.android.payment.data.PaymentStatus; import com.bluevia.android.payment.data.ServiceInfo; import com.bluevia.android.payment.parser.PaymentSerializer; import com.bluevia.android.payment.parser.xml.XmlPaymentParser; /** * This class provides access to the set of functions which any user could use to access * the Payment service functionality * * @author Telefonica R&D * */ public class BVPayment extends BVOauthClient { private static final String FEED_PAYMENT_BASE_URI = "/RPC/Payment"; protected static final String FEED_PAYMENT = "/payment"; protected static final String FEED_CANCEL_AUTHORIZATION = "/cancelAuthorization"; protected static final String FEED_GET_PAYMENT_STATUS = "/getPaymentStatus"; protected static final String METHOD_PAYMENT = "PAYMENT"; protected static final String METHOD_CANCEL_AUTHORIZATION = "CANCEL_AUTHORIZATION"; protected static final String METHOD_GET_PAYMENT_STATUS = "GET_PAYMENT_STATUS"; protected static final String OAUTH_API_NAME = "Payment"; protected static final String OAUTH_API_NAME_SANDBOX = "Payment_Sandbox"; protected static final String HEADER_TIMESTAMP = "oauth_timestamp"; /** * Constructor * * @param mode * @param consumerToken * @param consumerSecret * @throws BlueviaException */ public BVPayment(Mode mode, String consumerToken, String consumerSecret) throws BlueviaException { super(mode, consumerToken, consumerSecret); //Calling super to initialize OauthClient if (mode == Mode.TEST) throw new BlueviaException("Payment API only available in LIVE and SANDBOX mode", BlueviaException.INVALID_MODE_EXCEPTION); mEncoding = Encoding.APPLICATION_XML; mParser = new XmlPaymentParser(); mSerializer = new PaymentSerializer(); mBaseUri += buildUri(mMode, FEED_PAYMENT_BASE_URI); //Building base uri } /** * Gets a RequestToken for a Payment operation * * @param amount the cost of the digital good being sold, expressed in the minimum fractional monetary unit of the currency reflected in the next parameter (to avoid decimal digits). * @param currency the currency of the payment, following ISO 4217 (EUR, GBP, MXN, etc.). * @param name the name of the service for the payment * @param serviceId the id of the service for the payment * @return the request token * @throws BlueviaException */ public RequestToken getPaymentRequestToken(int amount, String currency, String name, String serviceId) throws BlueviaException { //Reset token ((IOAuth)mConnector).setOauthToken(null); ServiceInfo serviceInfo = new ServiceInfo(serviceId, name); PaymentInfo info = new PaymentInfo(amount, currency); PaymentRequestTokenParams request = new PaymentRequestTokenParams(serviceInfo, info); if (!request.isValid()) throw new BlueviaException("Bad request: Please, check function parameters", BlueviaException.BAD_REQUEST_EXCEPTION); byte[] data = serializeEntity(request); OAuthProviderListener listener = new BVPayentOauthProviderListener(); return super.getRequestToken(null, data, listener); } /** * OAuthProviderListener to manage the body data in the getPaymentRequestToken operation. * */ private class BVPayentOauthProviderListener implements OAuthProviderListener { @Override public void prepareSubmission(HttpRequest request) throws Exception {} @Override public void prepareRequest(HttpRequest request) throws Exception { //Include apiName header String apiName = ""; switch (mMode){ case LIVE: case TEST: apiName = OAUTH_API_NAME; break; case SANDBOX: apiName = OAUTH_API_NAME_SANDBOX; break; } request.setHeader("Authorization", "OAuth " + BVAuthorizationHeaderSigningStrategy.OAUTH_API_NAME + "=\"" + apiName + "\""); } @Override public boolean onResponseReceived(HttpRequest request, HttpResponse response) throws Exception { return false; } } /** * Gets an access token for a Payment operation * * @param oauthVerifier the OAuth verifier for the token * @param token the request token previously obtained * @param secret request token secret * @return the access token * @throws BlueviaException */ public OAuthToken getPaymentAccessToken(String oauthVerifier, String token, String secret) throws BlueviaException { OAuthToken accessToken = super.getAccessToken(oauthVerifier, token, secret); ((IOAuth)mConnector).setOauthToken(accessToken); return accessToken; } /** * * Orders an economic charge on the user's operator account. * * @param amount Amount to be charged, it may be an economic amount or a number of 'virtual units' (points, tickets, etc) (mandatory). * @param currency Type of currency which corresponds with the amount above, following ISO 4217 (mandatory). * @return Result of the payment operation. * @throws BlueviaException An exception informing about errors encountered in the request/response. * @throws IOException */ public PaymentResult payment(int amount, String currency) throws BlueviaException, IOException { return payment(amount, currency, null, null); } /** * * Orders an economic charge on the user's operator account. * @param amount Amount to be charged, it may be an economic amount or a number of 'virtual units' (points, tickets, etc) (mandatory). * @param currency Type of currency which corresponds with the amount above, following ISO 4217 (mandatory). * @param endpoint the endpoint to receive notifications of the payment operation * @param correlator the correlator * @return Result of the payment operation. * @throws BlueviaException An exception informing about errors encountered in the request/response. * @throws IOException */ public PaymentResult payment(int amount, String currency, String endpoint, String correlator) throws BlueviaException, IOException { Entity response; Entity responseEntity = null; PaymentInfo paymentInfo = new PaymentInfo(amount, currency); //Timestamp Format formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); Date date = new Date(); String timeStamp = formatter.format(date); String millis = String.valueOf(date.getTime()/1000); HashMap<String, String> additionalParams = new HashMap<String, String>(); additionalParams.put(HEADER_TIMESTAMP, millis); ((IOAuth)mConnector).setAdditionalParameters(additionalParams); MakePaymentParams params = new MakePaymentParams(timeStamp, paymentInfo, endpoint, correlator); MethodCall methodCall = new MethodCall(); methodCall.setMethod(METHOD_PAYMENT).setParamsEntity(params); if (!methodCall.isValid()) throw new BlueviaException("Bad request: Please, check function parameters", BlueviaException.BAD_REQUEST_EXCEPTION); HashMap<String, String> headers = new HashMap<String, String>(); headers.put(GsdpConstants.HEADER_CONTENT_TYPE, getEncoding(mEncoding)); HashMap<String, String> queryParams = new HashMap<String, String>(); queryParams.put(XmlConstants.PARAM_VERSION_KEY, XmlConstants.VERSION_1); response = this.create(FEED_PAYMENT, methodCall, queryParams, headers); if ((response == null) || (!(response instanceof MethodResponse))) throw new BlueviaException( "Error during request. Response received does not correspond to a " + MethodResponse.class.getName(), BlueviaException.INTERNAL_CLIENT_ERROR); responseEntity = ((MethodResponse) response).getResponseEntity(); if ((responseEntity == null) || (!(responseEntity instanceof PaymentResult))) throw new BlueviaException("Error during request. Response received does not correspond to a " + PaymentResult.class.getName(), BlueviaException.INTERNAL_CLIENT_ERROR); PaymentResult paymentResult = (PaymentResult) responseEntity; return paymentResult; } /** * Merchant can use this operation to invalidate the access token of the session. * If the payment has been made before, it remains valid, but no more getPaymentStatus operations will be enabled. * * @throws IOException * @throw BlueviaException An exception informing about errors encountered in the request/response. */ public void cancelAuthorization() throws BlueviaException, IOException { MethodCall methodCall = new MethodCall(); methodCall.setMethod(METHOD_CANCEL_AUTHORIZATION); if (!methodCall.isValid()) throw new BlueviaException("Bad request: Please, check function parameters", BlueviaException.BAD_REQUEST_EXCEPTION); HashMap<String, String> headers = new HashMap<String, String>(); headers.put(GsdpConstants.HEADER_CONTENT_TYPE, getEncoding(mEncoding)); HashMap<String, String> queryParams = new HashMap<String, String>(); queryParams.put(XmlConstants.PARAM_VERSION_KEY, XmlConstants.VERSION_1); Entity response = this.create(FEED_CANCEL_AUTHORIZATION, methodCall, queryParams, headers); if ((response == null) || (!(response instanceof MethodResponse))) throw new BlueviaException( "Error during request. Response received does not correspond to an " + MethodResponse.class.getName(), BlueviaException.INTERNAL_CLIENT_ERROR); } /** * Retrieves the status of a previous payment operation * * @param transactionId the id of the transaction * @return the status of the payment * @throws BlueviaException * @throws IOException */ public PaymentStatus getPaymentStatus(String transactionId) throws BlueviaException, IOException{ GetPaymentStatusParams params = new GetPaymentStatusParams(transactionId); MethodCall methodCall = new MethodCall(); methodCall.setMethod(METHOD_GET_PAYMENT_STATUS).setParamsEntity(params); if (!methodCall.isValid()) throw new BlueviaException("Bad request: Please, check function parameters", BlueviaException.BAD_REQUEST_EXCEPTION); HashMap<String, String> headers = new HashMap<String, String>(); headers.put(GsdpConstants.HEADER_CONTENT_TYPE, getEncoding(mEncoding)); HashMap<String, String> queryParams = new HashMap<String, String>(); queryParams.put(XmlConstants.PARAM_VERSION_KEY, XmlConstants.VERSION_1); Entity response = null; response = this.create(FEED_GET_PAYMENT_STATUS, methodCall, queryParams, headers); if ((response == null) || (!(response instanceof MethodResponse))) throw new BlueviaException( "Error during request. Response received does not correspond to a " + MethodResponse.class.getName(), BlueviaException.INTERNAL_CLIENT_ERROR); Entity responseEntity = ((MethodResponse) response).getResponseEntity(); if ((responseEntity == null) || (!(responseEntity instanceof PaymentStatus))) throw new BlueviaException("Error during request. Response received does not correspond to a " + PaymentStatus.class.getName(), BlueviaException.INTERNAL_CLIENT_ERROR); PaymentStatus paymentStatus = (PaymentStatus) responseEntity; return paymentStatus; } /** * Sets the access token of the session * This functions is used to change the token of the session to be able to get the * payment status of an old operation, or cancel the authorization of a token. * * @param accessToken */ public void setAccessToken(OAuthToken accessToken){ ((IOAuth)mConnector).setOauthToken(accessToken); } }