6.2 Getting a Transaction Notification

 < Day Day Up > 

When an order is processed, PayPal generates a notification that is then posted to the URL specified in the form as the hidden field notify_url. This is an example of a web service that relies on ordinary HTTP no fancy SOAP or other RPC underpinnings.

Using a simple HTTP request/response is perhaps the most basic, universal real world web service. It works with virtually every programming language and requires no special configuration to use. It's a classic case of the simple solution being the best solution.

Example 6-2 shows the JSP used to receive notifications from the PayPal server.

Example 6-2. Notification JSP
<%@ page contentType="text/html; charset=iso-8859-1"  language="java" import="com.cascadetg.ch06.*" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <%  new PayPalReciept( ).handleRequest(request, response);  response.setStatus(200); %>

The line response.setStatus(200) notifies PayPal that the notification has successfully been handled. By default, PayPal resends the notification until it gets a status code of 200 back, indicating that the transmission was successful. Disabling this line or substituting a different response code is an easy way to generate additional test load for your server without having to manually enter a lot of transactions.

The bulk of the work for this application is handled by supporting Java classes, as shown in Figure 6-5.

Figure 6-5. PayPal and Fax classes

The first class, shown in Example 6-3, exposes one main method, handleRequest(), to the JSP page. In the handleRequest( ) method, the first thing to be done is verify that the data sent by PayPal is correct with the verifyRequest( ) method. The verifyRequest( ) method retrieves the parameters sent by PayPal and then posts them back to PayPal via an HTTPS connection, with an additional parameter added (cmd=_notify-validate).

Example 6-3. A PayPal receipt
package com.cascadetg.ch06; import java.util.*; import java.net.*; import java.io.*; import javax.servlet.http.*; import javax.mail.*; import javax.mail.internet.*; public class PayPalReciept {     // Used to store retrived values from the PayPal submission.     String paymentStatus;     String txnId;     String receiverEmail;     String payerEmail;     private static final boolean debug = false;     // System.getProperty line to get the proper new line character[s].     String newLine = System.getProperty("line.separator", ".");     // Keep track of sent transactions. Note that this is in-memory     // storage only - for a "real" system you would want to persist     // this information, as well as the rest of fields of this object.     // (mostly likely to a database of some sort).     private static Hashtable processedTxnId = new Hashtable( );     // This method takes an incoming request and validates it both     // against the PayPal server and some internal logic.     public boolean validateRequest(HttpServletRequest request)     {         try         {             // Read the post from PayPal system.             Enumeration parameters = request.getParameterNames( );             // We then add a "cmd" attribute to send back to PayPal             // to indicate that we want to validate the request.             StringBuffer send =                 new StringBuffer("cmd=_notify-validate");             // Here, we put all of the parameters passed in from the             // PayPal notification POST.             while (parameters.hasMoreElements( ))             {                 String paramName = (String)parameters.nextElement( );                 String paramValue = request.getParameter(paramName);                 send.append("&");                 send.append(paramName);                 send.append("=");                 send.append(URLEncoder.encode(paramValue));             }             if (debug)                 System.out.println(send.toString( ));             // This next sequence opens a connection to the PayPal             // server, sets up the connection, and writes the sent             // parameters back to the PayPal server.             URL paypalServer =                 new URL("https://www.paypal.com/cgi-bin/webscr");             URLConnection paypalConnection =                 paypalServer.openConnection( );             paypalConnection.setDoOutput(true);             paypalConnection.setRequestProperty(                 "Content-Type",                 "application/x-www-form-urlencoded");             PrintWriter paypalServerWriter =                 new PrintWriter(paypalConnection.getOutputStream( ));             paypalServerWriter.println(send);             paypalServerWriter.close( );             if (debug)                 System.out.println("Sent to PayPal server.");             // We then need to read the response from the PayPal             // server.             BufferedReader in =                 new BufferedReader(                     new InputStreamReader(                         paypalConnection.getInputStream( )));             String paypalResponse = in.readLine( );             in.close( );             if (debug)                 System.out.println(                     "Read PayPal server response = " + paypalResponse);             // Set the values of this object from the values sent             // by the initial request. If these values are verified,             // we'll want them for later. If the values aren't             // verified, or something else is wrong, we'll want             // to track them for logging purposes.             setValues(request);             // If everything is ok, the response back should be             // VERIFIED. Otherwise, something went wrong.             if (paypalResponse.equals("VERIFIED"))             {                 // If it isn't completed, it's a status message of                 // some sort. We're only interested in Completed                 // payments.                 if (!paymentStatus.equals("Completed"))                     return false;                 // Make sure that we are the actual recipients of                 // the money.                 if (receiverEmail                     .compareToIgnoreCase(PayPalTokens.paypalEmail)                     != 0)                     return false;                 // Check the in-memory cache to verify that we                 // haven't already handled this transaction.                 if (processedTxnId.get(this.getTxnId( )) != null)                     return false;                 // Everything looks good, so let's add this to the                 // transaction cache.                 processedTxnId.put(this.getTxnId( ), this.getTxnId( ));                 return true;             } else             {                 System.out.println("Invalid PayPal transaction!");                 System.out.println(this.toString( ));                 return false;             }         } catch (Exception e)         {             System.out.println("Unable to connect to PayPal server.");             e.printStackTrace( );             return false;         }     }     // "Flatten" the object to a String.     public String toString( )     {         StringBuffer output = new StringBuffer( );         Enumeration outEnum = this.getAttributes( ).keys( );         while (outEnum.hasMoreElements( ))         {             String outputStr = (String)outEnum.nextElement( );             output.append(outputStr);             output.append(" : ");             output.append(paypalAttributes.get(outputStr).toString( ));             output.append(newLine);         }         return output.toString( );     }     public String toHTMLString( )     {         StringBuffer htmlString = new StringBuffer( );         htmlString.append("<HTML><BODY>");         htmlString.append("<TABLE HEIGHT='100%' WIDTH='100%'>");         htmlString.append("<TR><TD>");         Enumeration myValues = this.getAttributes( ).keys( );         while (myValues.hasMoreElements( ))         {             String next = (String)myValues.nextElement( );             htmlString.append(next);             htmlString.append(" : ");             htmlString.append(this.getAttribute(next).toString( ));             htmlString.append("<BR>");             htmlString.append(newLine);         }         htmlString.append("</TD></TR></TABLE></BODY></HTML>");         return htmlString.toString( );     }     // PayPal can send a variety of attributes back as part of a     // transaction. We're interested in all of them, so we'll note     // them all.     Hashtable paypalAttributes = new Hashtable( );     public String getAttribute(String attribute)     {         return (String)paypalAttributes.get((String)attribute);     }     public Hashtable getAttributes( )     {         return paypalAttributes;     }     /**      * Reads the incoming values and fills out the object. Notice that      * we are also recording the incoming IP address - if someone is      * sending fake requests, the IP address can be an important bit of      * information.      *       * @param request      */     private void setValues(HttpServletRequest request)     {         paypalAttributes = new Hashtable(request.getParameterMap( ));         Enumeration attributes = request.getParameterNames( );         while (attributes.hasMoreElements( ))         {             String temp = (String)attributes.nextElement( );             paypalAttributes.put(temp, request.getParameter(temp));         }         paypalAttributes.put(             "incoming_ip",             request.getRemoteAddr( ).toString( ));         paymentStatus = request.getParameter("payment_status");         txnId = request.getParameter("txn_id");         receiverEmail = request.getParameter("receiver_email");         payerEmail = request.getParameter("payer_email");     }     /**      * The main entry point from the JSP page request. We'll look at      * the request and validate it, and depending on the results, we'll      * either send a notification email OR a fax and a notification      * email.      */     public void handleRequest(         HttpServletRequest request,         HttpServletResponse response)     {         if (validateRequest(request))         {             if (debug)                 System.out.print("Sending fax... " + this.toString( ));             FaxSender myFaxSender = new FaxSender( );             myFaxSender.setText(this.toHTMLString( ));             myFaxSender.setTextType(FaxSender.HTML);             if (debug)                 System.out.print("fax prepped...");             myFaxSender.sendFax( );             this.paypalAttributes.put(                 "fax_id",                 myFaxSender.getResult( ).toString( ));             if (debug)                 System.out.println("Fax sent.");         }         sendEmail(this.toString( ));     }     // These are the usual retrieval methods a'la the JavaBean     // patterns. Notice that there are only retrieval methods - no     // setters are provided.     public String getPayerEmail( )     {         return payerEmail;     }     public String getPaymentStatus( )     {         return paymentStatus;     }     public String getReceiverEmail( )     {         return receiverEmail;     }     /** Returns the transaction ID (aka TxnId) */     public String getTxnId( )     {         return txnId;     }     public void sendEmail(String text)     {         try         {             java.util.Properties myProperties = new Properties( );             myProperties.put("mail.smtp.host", PayPalTokens.mailhost);             myProperties.put("mail.smtp.auth", "true");             Session mySession = Session.getInstance(myProperties);             //mySession.setDebug(true);             Transport myTransport = mySession.getTransport("smtp");             myTransport.connect(                 PayPalTokens.mailhost,                 PayPalTokens.mailhost_username,                 PayPalTokens.mailhost_password);             Message myMessage =                 new javax.mail.internet.MimeMessage(mySession);             myMessage.setFrom(                 new InternetAddress(                     PayPalTokens.paypalEmail,                     "PayPal Listener"));             myMessage.addRecipient(                 Message.RecipientType.TO,                 new InternetAddress(PayPalTokens.paypalEmail));             myMessage.setSubject("PayPal Notification");             myMessage.setContent(this.toHTMLString( ), "text/html");             Address[] temp =                 { new InternetAddress(PayPalTokens.paypalEmail)};             myMessage.setReplyTo(temp);             myMessage.saveChanges( );             myTransport.sendMessage(                 myMessage,                 myMessage.getAllRecipients( ));             myTransport.close( );         } catch (Exception e)         {             e.printStackTrace( );         }     }     public static void main(String[] args)     {         (new PayPalReciept( )).sendEmail("test");     } }

If PayPal doesn't respond with a VERIFIED token, it's possible that someone is attempting to forge a transaction. If you see this occur in a real world environment, you should take immediate, aggressive steps to deal with this; it may be an attempt by a hacker to steal funds or even your identity.

     < Day Day Up > 

    Real World Web Services
    Real World Web Services
    ISBN: 059600642X
    EAN: 2147483647
    Year: 2006
    Pages: 83
    Authors: Will Iverson

    Similar book on Amazon

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net