Monday, May 23, 2011

Switching between PayPal live and test environments

When you want to go live with your PayPal web application, you will have to modify your PayPal code to use the live PayPal sever (paypal.com) instead of the test server you've probably been using (sandbox.paypal.com). This is an easy task and doesn't take much time, but what if you want to still continue to use the PayPal test environment on your test server, while using the live PayPal environment on your production server?

I'm going to explain one approach to solving this problem here. The example I'm giving uses JSF and Facelets, but it can easily be adapted to any framework.

The first thing you'll need to do is add an entry to your web.xml and add the following entry:
<context-param>
<param-name>APPLICATION.MODE</param-name>
<param-value>$APPLICATION.MODE.VALUE$</param-value>
</context-param>
What this does is define an initialization parameter on the servlet context, which determines the environment we're in. The "param-value" will be "production" on your production machine, or anything else on your test machine.

The next step is to define a listener on the web application. This listener will take the initialization parameter we just defined and bind it in the application (=servlet) context, so it can be accessed in the entire web application. You'll need to edit your web.xml file again and add the following entry:
<listener>
<listener-class>com.myorg.MyListener</listener-class>
</listener>
The code for the listener is as follows:
public class MyListener implements ServletContextListener {

@Override
public void contextDestroyed(ServletContextEvent arg0) {
}

@Override
public void contextInitialized(ServletContextEvent event) {
String mode = event.getServletContext().getInitParameter("APPLICATION.MODE");
event.getServletContext().setAttribute("APPLICATION.MODE", mode);
}

}
As you can see, this class just takes the initialization parameter you defined and adds it as an attribute to the servlet context.

The next step is framework-specific. I'm using JSF with facelets, so I defined a facelet for a "buy now" PayPal button. The facelet is called "paypalButton.xhtml", and this is how it looks:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:composition>
<h:panelGroup
rendered="#{applicationScope['APPLICATION.MODE'] == 'production'}">
<form action="https://www.paypal.com/cgi-bin/webscr" method="post"><input
type="hidden" name="cmd" value="_s-xclick" /> <input type="hidden"
name="hosted_button_id" value="#{prodButtonId}" /> <input type="image"
src="https://www.paypalobjects.com/WEBSCR-640-20110429-1/en_US/i/btn/btn_buynowCC_LG.gif"
border="0" name="submit"
alt="PayPal - The safer, easier way to pay online!" /> <img alt=""
border="0"
src="https://www.paypalobjects.com/WEBSCR-640-20110429-1/en_US/i/scr/pixel.gif"
width="1" height="1" /></form>
</h:panelGroup>
<h:panelGroup
rendered="#{applicationScope['APPLICATION.MODE'] != 'production'}">
<form action="https://www.sandbox.paypal.com/cgi-bin/webscr"
method="post"><input type="hidden" name="cmd"
value="_s-xclick" /> <input type="hidden" name="hosted_button_id"
value="#{testButtonId}" /><input type="image"
src="https://www.sandbox.paypal.com/WEBSCR-640-20110401-1/en_US/i/btn/btn_buynowCC_LG.gif"
border="0" name="submit"
alt="PayPal - The safer, easier way to pay online!" /> <img alt=""
border="0"
src="https://www.sandbox.paypal.com/WEBSCR-640-20110401-1/en_US/i/scr/pixel.gif"
width="1" height="1" /></form>
</h:panelGroup>
</ui:composition>
</html>
As you can see, this facelet renders a live "buy now" button if the APPLICATION.MODE equals "production" or a sandbox "buy now" button otherwise. You can then call this facelet as follows (from another facelet):
<ui:include src="/paypalButton.xhtml">
<ui:param name="prodButtonId" value="XXX" />
<ui:param name="testButtonId" value="YYY" />
</ui:include>
In my case I'm using buttons that are stored with PayPal, so the only parameter I need is the button id. If you're creating your own buttons, you can easily define different parameters for the facelet.

After performing these steps, you have a system renders a live or sandbox button based on the value of the APPLICATION.MODE parameter that you defined in your web.xml. To prevent having to modify this parameter by hand, you can have your build system fill it out. What I did was create 2 ant files: buildTest.xml and buildProd.xml. buildTest sets this parameter to "test", while buildProd sets it to "production". This way all I have to do is execute the correct ant file and I have the correct PayPal buttons for my environment!

1 comment:

  1. Excellent post. Do you have any post for webfirmframework?

    ReplyDelete