One of the more odd parts of our architecture at work involves a cluster of Tomcat instances running ColdFusion and Java services side by side. We are porting our existing ColdFusion services over to Java/SpringMVC applications, and during the transition they are being served up by the same app servers.

One of these services interacts with Paypal/PayflowPro. We have a ColdFusion Component (CFC) that makes raw HTTP calls to PayflowPro, and has been behaving quite nicely for years. The service has been converted to Java, and has great test coverage and works great until deployed to Tomcat. When talking to PayflowPro, I get this rather unhelpful error message:
Failed to connect to host Input Server Uri= https://pilot-payflowpro.paypal.com:443
Failed to connect? Im running on the same box, same JDK, no proxy in the way, what could be wrong? Doing some digging, a few people had issues with needing to install SSL certs into their JDK, but again, I was using the exact same JDK. I hoped to avoid dealing with certs, so I kept looking. Another developer on our team had issues with PayfloPro’s API messing with the system-wide proxy settings, so he suggested to dump the system properties. I didn’t see the proxy settings being changed, but this did catch my eye:
java.protocol.handler.pkgs=com.sun.net.ssl.internal.www.protocol
Around this time I was also digging into how to turn on debug logging for Payflow’s SDK. A lot of their documentation is in a PDF, so here is the relevant code:

SDKProperties.setLogFileName("C:/temp/payflow.log");
SDKProperties.setLoggingLevel(PayflowConstants.SEVERITY_DEBUG);
SDKProperties.setMaxLogFileSize(1000000);

Re-running my transaction, the following appeared in the log:

paypal.payflow.PaymentConnection.CreateConnection(): Caught Exception creating connection: java.lang.ClassCastException: com.sun.net.ssl.internal.www.protocol.https.HttpsURLConnectionOldImpl cannot be cast to javax.net.ssl.HttpsURLConnection
at paypal.payflow.m.l(Unknown Source)
at paypal.payflow.m.f(Unknown Source)
at paypal.payflow.j.a(Unknown Source)
at paypal.payflow.a.j(Unknown Source)
at paypal.payflow.PayflowAPI.submitTransaction(Unknown Source)
at paypal.payflow.BaseTransaction.submitTransaction(Unknown Source)

Sure enough, Payflow seems to be written against javax.net.ssl, but the JVM is dealing with com.sun.net.ssl. Doing a little more digging around Google I came across the solution. The following change to the BAT file that launches my development Tomcat instance:
set JAVA_OPTS=%JAVA_OPTS% -Djava.protocol.handler.pkgs=javax.net.ssl