/* ******************************************************************
Copyright 2010 Xu Hui Hui (http://xhh.me)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
****************************************************************** */
package me.xhh.paypal;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
/**
* Handler to verify IPN (Instant Payment Notification) from PayPal.<br/>
* Examples:<br/>
* FIXME add examples
* @author xhh
*/
public class PayPalIPNHandler {
private static final String PayPal_IPN_URL = "https://www.paypal.com/cgi-bin/webscr";
private static final String PayPal_IPN_URL_SANDBOX = "https://www.sandbox.paypal.com/cgi-bin/webscr";
private static final int IPN_MAX_OPTIONS = 7;
private static final String IPN_OPTION_NAME = "option_name";
private static final String IPN_OPTION_SELECTION = "option_selection";
private static final String TOKEN_VERIFIED = "VERIFIED";
protected String itemNumber;
private final HttpServletRequest request;
private Map<String, Object> params;
private boolean useSandbox = false;
private Boolean verified = null;
private String paramStr;
private String business;
private String itemName;
private String paymentStatus;
private String paymentAmount;
private String paymentCurrency;
private String txnId;
private String payerEmail;
private String receiverEmail;
private String paymentType;
private String txnType;
/**
* @param request the HttpServletRequest. Make sure the request is valid in the
* process of handling.
*/
@SuppressWarnings("unchecked")
public PayPalIPNHandler(HttpServletRequest request) throws ServletException, IOException {
this.request = request;
this.params = request.getParameterMap();
if (params == null)
params = new HashMap<String, Object>(0);
}
/**
* Send request to PayPal to verify the current event
* @param request
*/
@SuppressWarnings("unchecked")
public synchronized void verify() throws ServletException, IOException {
if (verified != null) // already done before
return;
// build verify-info
Enumeration keys = request.getParameterNames();
String verifyStr = "cmd=_notify-validate";
while (keys.hasMoreElements()) {
String paramName = (String) keys.nextElement();
String paramValue = request.getParameter(paramName);
verifyStr = verifyStr + "&" + paramName + "=" + URLEncoder.encode(paramValue, "UTF-8");
}
// send verify-info
URL u = new URL(useSandbox ? PayPal_IPN_URL_SANDBOX : PayPal_IPN_URL);
URLConnection uc = u.openConnection();
uc.setDoOutput(true);
uc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
OutputStreamWriter writer = new OutputStreamWriter(uc.getOutputStream(), "UTF-8");
writer.write(verifyStr);
writer.close();
// receive verify-result
BufferedReader in = new BufferedReader(new InputStreamReader(uc.getInputStream(), "UTF-8"));
String result = in.readLine();
in.close();
paramStr = verifyStr;
itemName = request.getParameter("item_name");
itemNumber = request.getParameter("item_number");
paymentType = request.getParameter("payment_type");
paymentStatus = request.getParameter("payment_status");
paymentAmount = request.getParameter("mc_gross");
paymentCurrency = request.getParameter("mc_currency");
txnType = request.getParameter("txn_type");
txnId = request.getParameter("txn_id");
business = request.getParameter("business");
receiverEmail = request.getParameter("receiver_email");
payerEmail = request.getParameter("payer_email");
verified = TOKEN_VERIFIED.equals(result);
}
public boolean isVerified() throws ServletException, IOException {
if (verified == null)
verify();
return verified;
}
public String getOption(String name) {
if (name == null)
return null;
for (int i=1; i<=IPN_MAX_OPTIONS; i++) {
try {
String[] keys = (String[]) params.get(IPN_OPTION_NAME + i);;
if (keys == null)
continue;
for (int j=0; j<keys.length; j++) {
if (name.equals(keys[j])) {
String[] values = (String[]) params.get(IPN_OPTION_SELECTION + i);
return (values==null || values.length<=j) ? null : values[j];
}
}
} catch (ClassCastException e) {
return null;
}
}
// not found
return null;
}
public boolean isUseSandbox() {
return useSandbox;
}
public void setUseSandbox(boolean useSandbox) {
this.useSandbox = useSandbox;
}
public String getItemName() {
return itemName;
}
public String getItemNumber() {
return itemNumber;
}
public String getPaymentStatus() {
return paymentStatus;
}
public String getPaymentAmount() {
return paymentAmount;
}
public String getPaymentCurrency() {
return paymentCurrency;
}
public String getTransactionId() {
return txnId;
}
public String getReceiverEmail() {
return receiverEmail;
}
public String getPayerEmail() {
return payerEmail;
}
public String getBusiness() {
return business;
}
/**
* The verify() or isVerified() method must be executed before this is called
* @return the verification string, with all parameters got after "cmd=_notify-validate"
*/
public String getParamStr() {
return paramStr;
}
public String getPaymentType() {
return paymentType;
}
public String getTransactionType() {
return txnType;
}
}