Skip to content

Commit 5f58e55

Browse files
committed
Http Library changes
1 parent 6e2003d commit 5f58e55

4 files changed

Lines changed: 252 additions & 12 deletions

File tree

java/src/main/java/com/cybersource/ws/client/Client.java

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.io.FileInputStream;
3535
import java.io.IOException;
3636
import java.io.StringReader;
37+
import java.lang.reflect.InvocationTargetException;
3738
import java.security.KeyStore;
3839
import java.security.cert.PKIXParameters;
3940
import java.security.cert.TrustAnchor;
@@ -90,13 +91,15 @@ public static Map runTransaction(Map<String,String> request, Properties props)
9091
* @throws FaultException if a fault occurs.
9192
* @throws ClientException if any other exception occurs.
9293
*/
93-
public static Map runTransaction(
94+
@SuppressWarnings("unchecked")
95+
public static Map runTransaction(
9496
Map<String, String> request, Properties props,
9597
Logger _logger, boolean prepare, boolean logTranStart)
9698
throws FaultException, ClientException {
9799
MerchantConfig mc;
98100
LoggerWrapper logger = null;
99101
Connection con = null;
102+
Object client_class_obj;
100103

101104
try {
102105
setVersionInformation(request);
@@ -122,8 +125,33 @@ public static Map runTransaction(
122125
// FileWriter writer = new FileWriter(new File("signedDoc.xml"));
123126
// writer.write(XMLUtils.PrettyDocumentToString(signedDoc));
124127
// writer.close();
125-
126-
con = Connection.getInstance(mc, builder, logger);
128+
if(mc.isClientHttpFactoryEnabled()){
129+
Class<Connection> custom_connection_class;
130+
try {
131+
custom_connection_class = (Class<Connection>) Class.forName(mc.getUseClientHttpFactory());
132+
Class[] constructor_Args = new Class[] {com.cybersource.ws.client.MerchantConfig.class, javax.xml.parsers.DocumentBuilder.class, com.cybersource.ws.client.LoggerWrapper.class};
133+
con=custom_connection_class.getDeclaredConstructor(constructor_Args).newInstance(mc, builder, logger);
134+
//con=((Connection) client_class_obj).getConnection();
135+
} catch (InstantiationException e) {
136+
throw new ClientException(e, false, null);
137+
} catch (IllegalAccessException e) {
138+
throw new ClientException(e, false, null);
139+
} catch (ClassNotFoundException e) {
140+
System.out.println("could not load class amazon "+e);
141+
throw new ClientException(e, false, null);
142+
} catch (IllegalArgumentException e) {
143+
throw new ClientException(e, false, null);
144+
} catch (SecurityException e) {
145+
throw new ClientException(e, false, null);
146+
} catch (InvocationTargetException e) {
147+
throw new ClientException(e, false, null);
148+
} catch (NoSuchMethodException e) {
149+
throw new ClientException(e, false, null);
150+
}
151+
}
152+
else{
153+
con = Connection.getInstance(mc, builder, logger);
154+
}
127155
Document wrappedReply = con.post(signedDoc);
128156
Map<String, String> replyMap = soapUnwrap(wrappedReply, mc, logger);
129157
logger.log(Logger.LT_INFO, "Client, End of runTransaction Call ",false);

java/src/main/java/com/cybersource/ws/client/MerchantConfig.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,13 @@ public class MerchantConfig {
6565
private String proxyPassword;
6666
private String cacertPassword;
6767
private String useClientHttpFactory;
68-
private boolean useClientHttpFactoryFlag;
68+
private boolean ClientHttpFactoryEnabled;
6969

7070
public String getUseClientHttpFactory() {
7171
return useClientHttpFactory;
7272
}
73-
public boolean getUseClientHttpFactoryFlag() {
74-
return useClientHttpFactoryFlag;
73+
public boolean isClientHttpFactoryEnabled() {
74+
return ClientHttpFactoryEnabled;
7575
}
7676
// computed values
7777
private String effectiveServerURL;
@@ -270,7 +270,7 @@ public MerchantConfig(Properties _props, String _merchantID)
270270
enableJdkCert = getBooleanProperty(merchantID, "enableJdkCert", false);
271271
enableCacert=getBooleanProperty(merchantID, "enableCacert", false);
272272
cacertPassword=getProperty(merchantID,"cacertPassword","changeit");
273-
useClientHttpFactoryFlag=getBooleanProperty(merchantID,"useClientHttpFactoryFlag",false);
273+
ClientHttpFactoryEnabled=getBooleanProperty(merchantID,"ClientHttpFactoryEnabled",false);
274274
// compute and store effective namespace URI
275275

276276
if (namespaceURI == null && targetAPIVersion == null) {
@@ -474,7 +474,7 @@ public String getLogString() {
474474
appendPair(sb, "logFilename", logFilename);
475475
appendPair(sb, "logMaximumSize", logMaximumSize);
476476
appendPair(sb, "useClientHttpFactory", useClientHttpFactory);
477-
appendPair(sb, "useClientHttpFactoryFlag", useClientHttpFactoryFlag);
477+
appendPair(sb, "useClientHttpFactoryFlag", ClientHttpFactoryEnabled);
478478
appendPair(sb, "useHttpClient", useHttpClient);
479479
appendPair(sb, "enableJdkCert", enableJdkCert);
480480
appendPair(sb, "enableCacert", enableCacert);

java/src/main/java/com/cybersource/ws/client/XMLClient.java

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import java.io.ByteArrayOutputStream;
3636
import java.io.IOException;
3737
import java.io.StringReader;
38+
import java.lang.reflect.InvocationTargetException;
3839
import java.util.Properties;
3940

4041
/**
@@ -64,7 +65,8 @@ public class XMLClient {
6465

6566
private static Document soapEnvelope;
6667
private static Exception initException = null;
67-
68+
private static Object client_class_obj;
69+
private static Class<Connection> clientclass;
6870
static {
6971
try {
7072
// load the SOAP envelope document.
@@ -137,7 +139,8 @@ public static Document runTransaction(Document request, Properties props)
137139
* @throws FaultException if a fault occurs.
138140
* @throws ClientException if any other exception occurs.
139141
*/
140-
public static Document runTransaction(
142+
@SuppressWarnings("unchecked")
143+
public static Document runTransaction(
141144
Document request, Properties props,
142145
Logger _logger, boolean prepare, boolean logTranStart)
143146
throws FaultException, ClientException {
@@ -177,8 +180,32 @@ public static Document runTransaction(
177180

178181
Document signedDoc
179182
= soapWrapAndSign(request, mc, builder, logger);
180-
181-
con = Connection.getInstance(mc, builder, logger);
183+
if(mc.isClientHttpFactoryEnabled()){
184+
Class<Connection> custom_connection_class;
185+
try {
186+
custom_connection_class = (Class<Connection>) Class.forName(mc.getUseClientHttpFactory());
187+
Class[] constructor_Args = new Class[] {com.cybersource.ws.client.MerchantConfig.class, javax.xml.parsers.DocumentBuilder.class, com.cybersource.ws.client.LoggerWrapper.class};
188+
con=custom_connection_class.getDeclaredConstructor(constructor_Args).newInstance(mc, builder, logger);
189+
//con=((Connection) client_class_obj).getConnection();
190+
} catch (InstantiationException e) {
191+
throw new ClientException(e, false, null);
192+
} catch (IllegalAccessException e) {
193+
throw new ClientException(e, false, null);
194+
} catch (ClassNotFoundException e) {
195+
throw new ClientException(e, false, null);
196+
} catch (IllegalArgumentException e) {
197+
throw new ClientException(e, false, null);
198+
} catch (SecurityException e) {
199+
throw new ClientException(e, false, null);
200+
} catch (InvocationTargetException e) {
201+
throw new ClientException(e, false, null);
202+
} catch (NoSuchMethodException e) {
203+
throw new ClientException(e, false, null);
204+
}
205+
}
206+
else{
207+
con = Connection.getInstance(mc, builder, logger);
208+
}
182209
Document wrappedReply = con.post(signedDoc);
183210

184211
Document doc = soapUnwrap(wrappedReply, mc, builder, logger);
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
package com.cybersource.ws.client;
2+
3+
import java.io.ByteArrayOutputStream;
4+
import java.io.IOException;
5+
import java.io.InputStream;
6+
import java.net.MalformedURLException;
7+
import java.net.ProtocolException;
8+
import java.util.ArrayList;
9+
import java.util.HashMap;
10+
import java.util.List;
11+
12+
import javax.xml.parsers.DocumentBuilder;
13+
import javax.xml.transform.TransformerConfigurationException;
14+
import javax.xml.transform.TransformerException;
15+
16+
import org.apache.commons.httpclient.HttpClient;
17+
import org.apache.commons.httpclient.HttpMethod;
18+
import org.apache.commons.httpclient.HttpMethodRetryHandler;
19+
import org.apache.commons.httpclient.HttpState;
20+
import org.apache.commons.httpclient.NoHttpResponseException;
21+
import org.apache.commons.httpclient.UsernamePasswordCredentials;
22+
import org.apache.commons.httpclient.auth.AuthPolicy;
23+
import org.apache.commons.httpclient.auth.AuthScope;
24+
import org.apache.commons.httpclient.methods.PostMethod;
25+
import org.apache.commons.httpclient.methods.StringRequestEntity;
26+
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
27+
import org.apache.commons.httpclient.params.HttpMethodParams;
28+
import org.w3c.dom.Document;
29+
30+
31+
public class AmazonHttpConnection extends Connection{
32+
private PostMethod postMethod = null;
33+
34+
AmazonHttpConnection(MerchantConfig mc, DocumentBuilder builder, LoggerWrapper logger) {
35+
super(mc, builder, logger);
36+
}
37+
38+
@Override
39+
public boolean isRequestSent() {
40+
return postMethod != null && postMethod.isRequestSent();
41+
}
42+
@Override
43+
public void release() {
44+
if (postMethod != null) {
45+
postMethod.releaseConnection();
46+
postMethod = null;
47+
}
48+
}
49+
50+
@Override
51+
void postDocument(Document request) throws IOException,
52+
TransformerConfigurationException, TransformerException,
53+
MalformedURLException, ProtocolException {
54+
HttpClient httpClient = new HttpClient();
55+
setTimeout(httpClient, mc.getTimeout() * 1000);
56+
setProxy(httpClient);
57+
58+
String serverURL = mc.getEffectiveServerURL();
59+
postMethod = new PostMethod(serverURL);
60+
postMethod.getParams().setParameter(
61+
HttpMethodParams.RETRY_HANDLER, new MyRetryHandler());
62+
63+
String requestString = documentToString(request);
64+
logger.log(Logger.LT_INFO,
65+
"Sending " + requestString.length() + " bytes to " + serverURL);
66+
67+
postMethod.setRequestEntity(
68+
new StringRequestEntity(requestString, null, "UTF-8"));
69+
70+
httpClient.executeMethod(postMethod);
71+
72+
}
73+
@Override
74+
int getHttpResponseCode() throws IOException {
75+
return postMethod != null ? postMethod.getStatusCode() : -1;
76+
}
77+
@Override
78+
InputStream getResponseStream() throws IOException {
79+
return postMethod != null ? postMethod.getResponseBodyAsStream() : null;
80+
}
81+
@Override
82+
InputStream getResponseErrorStream() throws IOException {
83+
return getResponseStream();
84+
}
85+
/**
86+
* This method is useful in Client environment where Firewall is set to prevent accessing the external services.
87+
* Proxy settings are required in such scenarios.
88+
* @param httpClient
89+
*/
90+
private void setProxy(HttpClient httpClient) {
91+
if (mc.getProxyHost() != null) {
92+
httpClient.getHostConfiguration().setProxy(
93+
mc.getProxyHost(), mc.getProxyPort());
94+
95+
if (mc.getProxyUser() != null) {
96+
List<String> authPrefs = new ArrayList<String>();
97+
authPrefs.add(AuthPolicy.BASIC);
98+
httpClient.getParams().setParameter(
99+
AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
100+
101+
HttpState state = new HttpState();
102+
state.setProxyCredentials(
103+
AuthScope.ANY,
104+
new UsernamePasswordCredentials(
105+
mc.getProxyUser(), mc.getProxyPassword()));
106+
httpClient.setState(state);
107+
}
108+
}
109+
}
110+
111+
/**
112+
* Method converts Document to String using java.xml package library.
113+
* @param doc - Document object
114+
* @return - String object
115+
* @throws TransformerConfigurationException
116+
* @throws TransformerException
117+
* @throws IOException
118+
*/
119+
private static String documentToString(Document doc)
120+
throws TransformerConfigurationException, TransformerException,
121+
IOException {
122+
ByteArrayOutputStream baos = null;
123+
try {
124+
baos = makeStream(doc);
125+
return baos.toString("utf-8");
126+
} finally {
127+
if (baos != null) {
128+
baos.close();
129+
}
130+
}
131+
}
132+
133+
/**
134+
* Methods helps to set the timeout for HTTP request call.
135+
* cybs.properties can be used to configure the timeout details.
136+
* @param httpClient
137+
* @param timeoutInMs
138+
*/
139+
private void setTimeout(HttpClient httpClient, int timeoutInMs) {
140+
HttpConnectionManagerParams params
141+
= httpClient.getHttpConnectionManager().getParams();
142+
params.setConnectionTimeout(timeoutInMs);
143+
params.setSoTimeout(timeoutInMs);
144+
}
145+
146+
private class MyRetryHandler implements HttpMethodRetryHandler {
147+
148+
long retryWaitInterval=mc.getRetryInterval();
149+
int maxRetries= mc.getNumberOfRetries();
150+
151+
// I copied this code from
152+
// http://jakarta.apache.org/commons/httpclient/exception-handling.html#HTTP%20transport%20safety
153+
// and changed the NoHttpResponseException case to
154+
// return false.
155+
public boolean retryMethod(
156+
final HttpMethod method,
157+
final IOException exception,
158+
int executionCount) {
159+
if (executionCount > maxRetries) {
160+
// Do not retry if over max retry count
161+
return false;
162+
}
163+
if (exception instanceof NoHttpResponseException) {
164+
// Retry if the server dropped connection on us
165+
// return true; <-- this was the original behavior.
166+
return false;
167+
}
168+
if (!method.isRequestSent()) {
169+
// Retry if the request has not been sent fully or
170+
// if it's OK to retry methods that have been sent
171+
try {
172+
Thread.sleep(retryWaitInterval);
173+
logger.log( Logger.LT_INFO+" Retrying Request -- ",mc.getUniqueKey().toString()+ " Retry Count -- "+executionCount);
174+
} catch (InterruptedException e) {
175+
// TODO Auto-generated catch block
176+
e.printStackTrace();
177+
}
178+
return true;
179+
}
180+
// otherwise do not retry
181+
return false;
182+
}
183+
}
184+
185+
}

0 commit comments

Comments
 (0)