Rev 11436 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
package in.shop2020.payment.service.handler;import in.shop2020.config.ConfigException;import in.shop2020.payment.domain.Payment;import in.shop2020.thrift.clients.config.ConfigClient;import java.io.BufferedReader;import java.io.DataOutputStream;import java.io.IOException;import java.io.InputStreamReader;import java.io.StringReader;import java.net.ConnectException;import java.net.MalformedURLException;import java.net.URL;import java.net.URLConnection;import java.net.URLEncoder;import java.util.HashMap;import java.util.Map;import java.util.Map.Entry;import javax.xml.xpath.XPath;import javax.xml.xpath.XPathConstants;import javax.xml.xpath.XPathExpressionException;import javax.xml.xpath.XPathFactory;import org.apache.log4j.Logger;import org.w3c.dom.Element;import org.w3c.dom.NodeList;import org.xml.sax.InputSource;public class EbsPaymentHandler implements IPaymentHandler {private static Logger log = Logger.getLogger(Class.class);public static final String TXN_ID = "transactionId";public static final String PAYMENT_ID = "paymentId";public static final String AMOUNT = "amount";public static final String DATE_TIME = "dateTime";public static final String MODE = "mode";public static final String REF_NO = "referenceNo";public static final String TXN_TYPE = "transactionType";private static String accountId;private static String secretKey;static{try {accountId = ConfigClient.getClient().get("ebs_account_id");secretKey = ConfigClient.getClient().get("ebs_secret_key");} catch (ConfigException e) {log.error("Unable to get EBS payment configuration.", e);}}/*** Capture the amount which was authorized for this payment Id. Makes* requests over the network and so internet connectivity is must for it to* succeed.** @param amount* The amount to be captured. Must be the same value which was* authorized for this payment.* @param paymentId* The payment ID generated by the gateway.* @return A Map. The Map will definitely have status and will have error* information in case of error and txn information in case of* success. In case there is an error in processing, the returned* result map will be empty.*/public static Map<String, String> capturePayment(Payment payment){double amount = payment.getAmount();String paymentId = payment.getGatewayPaymentId();System.out.println("Capturing amount: Rs " + amount + " for payment Id: " + paymentId);URL url = null;URLConnection urlConn = null;DataOutputStream printout;BufferedReader reader;Map<String, String> resultMap = new HashMap<String, String>();//Prepare resultMap to elicit failure behaviour in case anything goes wrong.resultMap.put(STATUS, "");/** HDFC Insanity** If we don't set this property, all payments through HDFC will fail if* the first payment is made through EBS.** The JAR file provided by HDFC requires that the instances of* HttpsURLConnection returned by a call to URL.openConnection be an* instance of com.sun.net.ssl.HttpsURLConnection. Java versions before* 1.4 used to return an instance of this class which goes against the* current policy of using instances of undocumented internal classes of* JDK since they can change at any time. This behaviour was changed in* JAVA 1.4 to return instances of javax.net.ssl.HttpsURLConnection.* However, it appears, that to allow clients with JDK 1.4 and earlier,* HDFC favours the use of the deprecated class.*/System.setProperty("https.protocols", "TLSv1");try {// URL of CGI-Bin script.url = new URL("https://api.secure.ebs.in/api/1_0");// URL connection channel.urlConn = url.openConnection();//urlConn.setRequestMethod("POST");} catch (MalformedURLException e1) {log.error(Errors.CAPTURE_FAILURE.message, e1);resultMap.put(ERR_CODE, Errors.CAPTURE_FAILURE.code);resultMap.put(ERROR, Errors.CAPTURE_FAILURE.message);return resultMap;} catch (IOException e) {log.error("Unable to initialize connection to EBS API server", e);resultMap.put(ERR_CODE, Errors.CONN_FAILURE.code);resultMap.put(ERROR, Errors.CONN_FAILURE.message);return resultMap;}// Let the run-time system (RTS) know that we want input.urlConn.setDoInput (true);// Let the RTS know that we want to do output.urlConn.setDoOutput (true);// No caching, we want the real thing.urlConn.setUseCaches (false);// Specify the content type.urlConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");// Send POST output.try {printout = new DataOutputStream (urlConn.getOutputStream ());String content ="Action=" + URLEncoder.encode("capture", "UTF-8") +"&AccountID=" + URLEncoder.encode(accountId, "UTF-8") +"&SecretKey=" + URLEncoder.encode(secretKey, "UTF-8") +"&Amount=" + URLEncoder.encode(""+amount, "UTF-8") +"&PaymentID=" + URLEncoder.encode(paymentId, "UTF-8") +"&submitted=Submit";printout.writeBytes (content);printout.flush ();printout.close ();// Get response data.reader = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));resultMap = parseCaptureOutput(reader);reader.close ();}catch(ConnectException e) {log.error("Unable to initialize connection to EBS API server", e);resultMap.put(ERR_CODE, Errors.CONN_FAILURE.code);resultMap.put(ERROR, Errors.CONN_FAILURE.message);return resultMap;}catch (IOException e) {log.error(Errors.CAPTURE_FAILURE.message, e);resultMap.clear();resultMap.put(STATUS, "");resultMap.put(ERR_CODE, Errors.CAPTURE_FAILURE.code);resultMap.put(ERROR, Errors.CAPTURE_FAILURE.message);}return resultMap;}/*** Parses the given input stream and returns a map containing the* transaction details** @param reader The reader containing the response of the capture request.* @return A Map. The Map will definitely have status and will have error* information in case of error and txn information in case of* success.*/private static Map<String, String> parseCaptureOutput(BufferedReader reader){Map<String, String> resultMap = new HashMap<String, String>();resultMap.put(STATUS, "");String str = null;try {str = reader.readLine();log.info("Capture response: " + str);} catch (IOException e) {log.error("Error reading the capture response:", e);return resultMap;}InputSource inputSource = new InputSource(new StringReader(str));XPath xpath = XPathFactory.newInstance().newXPath();String expression = "/output";NodeList nodes = null;try {nodes = (NodeList) xpath.evaluate(expression, inputSource, XPathConstants.NODESET);} catch(XPathExpressionException xpee) {log.error("Input couldn't be parsed. See capture response for more info.");return resultMap;}Element elem = (Element) nodes.item(0);String status = elem.getAttribute(STATUS);resultMap.put(STATUS, status);if("".equals(status) || !"Processing".equals(status)){//We've received an error. Retrieve the error valuesresultMap.put(ERR_CODE, elem.getAttribute(ERR_CODE));resultMap.put(ERROR, elem.getAttribute(ERROR));}else{resultMap.put(CAPTURE_TXN_ID, elem.getAttribute(TXN_ID));resultMap.put(PAYMENT_ID, elem.getAttribute(PAYMENT_ID));resultMap.put(AMOUNT, elem.getAttribute(AMOUNT));resultMap.put(CAPTURE_TIME, elem.getAttribute(DATE_TIME));resultMap.put(MODE, elem.getAttribute(MODE));resultMap.put(REF_NO, elem.getAttribute(REF_NO));resultMap.put(TXN_TYPE, elem.getAttribute(TXN_TYPE));}log.info("Parsed capture response:");for(Entry<String, String> entry : resultMap.entrySet()){log.info("Key: " + entry.getKey() + ", Value: " + entry.getValue());}return resultMap;}/*** Refund the amount which was captured for this payment Id. Makes* requests over the network and so internet connectivity is must for it to* succeed.** @param amount* The amount to be refunded.* @param paymentId* The payment ID generated by the gateway.* @return A Map. The Map will definitely have status and will have error* information in case of error and txn information in case of* success. In case there is an error in processing, the returned* result map will be empty.*/public static Map<String, String> refundPayment(Payment payment, double amount){String paymentId = payment.getGatewayPaymentId();System.out.println("Refunding amount: Rs " + amount + " for payment Id: " + paymentId);URL url = null;URLConnection urlConn = null;DataOutputStream printout;BufferedReader reader;Map<String, String> resultMap = new HashMap<String, String>();//Prepare resultMap to elicit failure behaviour in case anything goes wrong.resultMap.put(STATUS, "");/** HDFC Insanity** If we don't set this property, all payments through HDFC will fail if* the first payment is made through EBS.** The JAR file provided by HDFC requires that the instances of* HttpsURLConnection returned by a call to URL.openConnection be an* instance of com.sun.net.ssl.HttpsURLConnection. Java versions before* 1.4 used to return an instance of this class which goes against the* current policy of using instances of undocumented internal classes of* JDK since they can change at any time. This behaviour was changed in* JAVA 1.4 to return instances of javax.net.ssl.HttpsURLConnection.* However, it appears, that to allow clients with JDK 1.4 and earlier,* HDFC favours the use of the deprecated class.*/System.setProperty("https.protocols", "TLSv1");try {// URL of CGI-Bin script.url = new URL("https://api.secure.ebs.in/api/1_0");// URL connection channel.urlConn = url.openConnection();//urlConn.setRequestMethod("POST");} catch (MalformedURLException e1) {log.error(Errors.CAPTURE_FAILURE.message, e1);resultMap.put(ERR_CODE, Errors.CAPTURE_FAILURE.code);resultMap.put(ERROR, Errors.CAPTURE_FAILURE.message);return resultMap;} catch (IOException e) {log.error("Unable to initialize connection to EBS API server", e);resultMap.put(ERR_CODE, Errors.CONN_FAILURE.code);resultMap.put(ERROR, Errors.CONN_FAILURE.message);return resultMap;}// Let the run-time system (RTS) know that we want input.urlConn.setDoInput (true);// Let the RTS know that we want to do output.urlConn.setDoOutput (true);// No caching, we want the real thing.urlConn.setUseCaches (false);// Specify the content type.urlConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");// Send POST output.try {printout = new DataOutputStream (urlConn.getOutputStream ());String content ="Action=" + URLEncoder.encode("refund", "UTF-8") +"&AccountID=" + URLEncoder.encode(accountId, "UTF-8") +"&SecretKey=" + URLEncoder.encode(secretKey, "UTF-8") +"&Amount=" + URLEncoder.encode(""+amount, "UTF-8") +"&PaymentID=" + URLEncoder.encode(paymentId, "UTF-8") +"&submitted=Submit";printout.writeBytes (content);printout.flush ();printout.close ();// Get response data.reader = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));resultMap = parseCaptureOutput(reader);resultMap.put(REFUND_TXN_ID, resultMap.get(CAPTURE_TXN_ID));resultMap.put(REFUND_TIME, resultMap.get(CAPTURE_TIME));resultMap.remove(CAPTURE_TXN_ID);resultMap.remove(CAPTURE_TIME);reader.close ();}catch(ConnectException e) {log.error("Unable to initialize connection to EBS API server", e);resultMap.put(ERR_CODE, Errors.CONN_FAILURE.code);resultMap.put(ERROR, Errors.CONN_FAILURE.message);return resultMap;}catch (IOException e) {log.error(Errors.CAPTURE_FAILURE.message, e);resultMap.clear();resultMap.put(STATUS, "");resultMap.put(ERR_CODE, Errors.CAPTURE_FAILURE.code);resultMap.put(ERROR, Errors.CAPTURE_FAILURE.message);}return resultMap;}public static void main(String[] args){Payment p = new Payment();p.setGatewayPaymentId("30573297");p.setAmount(20);capturePayment(p);}}