1
2
3
4
5
6
7
8
9 package org.astrogrid.applications.http;
10
11 import org.apache.commons.logging.Log;
12 import org.apache.commons.logging.LogFactory;
13
14 import java.io.IOException;
15 import java.net.MalformedURLException;
16 import java.util.Iterator;
17 import java.util.Map;
18 import java.util.Set;
19
20 import org.apache.commons.httpclient.HttpClient;
21 import org.apache.commons.httpclient.HttpException;
22 import org.apache.commons.httpclient.HttpMethod;
23 import org.apache.commons.httpclient.HttpRecoverableException;
24 import org.apache.commons.httpclient.NameValuePair;
25 import org.apache.commons.httpclient.URIException;
26 import org.apache.commons.httpclient.methods.GetMethod;
27 import org.apache.commons.httpclient.methods.PostMethod;
28 import org.astrogrid.applications.http.exceptions.HttpApplicationNetworkException;
29 import org.astrogrid.applications.http.exceptions.HttpApplicationWebServiceURLException;
30 ;
31
32 /***
33 * Talks to the http get or post service and post-processes the response.
34 * @TODO think about big results...streaming, char encoding etc
35 * @TODO how are we going to test?
36 *
37 * @author jdt
38 */
39 public class HttpServiceClient {
40 /***
41 * Logger for this class
42 */
43 private static final Log log = LogFactory.getLog(HttpServiceClient.class);
44
45 /***
46 * The get or set method to call on the server.
47 */
48 private HttpMethod method;
49 /***
50 * The client that processes the methods.
51 * @TODO can we make this static?
52 */
53 private HttpClient client = new HttpClient();
54 /***
55 * Number of attempts we make before giving up.
56 * @TODO consider making this a property.
57 */
58 private static final int MAX_ATTEMPTS = 3;
59 private static final int NOT_FOUND = 404;
60
61 /***
62 * Represents if the httpservice is a get or a post. java enum idiom
63 *
64 * @author jdt
65 *
66 */
67 public static class HttpServiceType {
68 /***
69 * Logger for this class
70 */
71 private static final Log log = LogFactory.getLog(HttpServiceType.class);
72
73 public static HttpServiceType GET = new HttpServiceType("get");
74
75 public static HttpServiceType POST = new HttpServiceType("post");
76
77 public static HttpServiceType TEST = new HttpServiceType("mock");
78
79 private String type;
80
81 /***
82 * ctor
83 *
84 * @param type name of the type
85 */
86 private HttpServiceType(final String type) {
87 this.type = type;
88 }
89
90 public String toString() {
91 return type;
92 }
93 }
94
95 /***
96 * Constructor
97 * Note - the constructor may throw an IllegalArgumentException
98 * if this URI is invalid. Not my fault - that's what the underlying
99 * commons-http library does.
100 */
101 public HttpServiceClient(final String serviceUrl, final HttpServiceType serviceType) {
102 if (log.isTraceEnabled()) {
103 log.trace("HttpServiceClient(String serviceUrl = " + serviceUrl + ", HttpServiceType serviceType = "
104 + serviceType + ") - start");
105 }
106
107 if (serviceType==HttpServiceType.GET) {
108 method = new GetMethod(serviceUrl);
109 } else if (serviceType==HttpServiceType.POST) {
110 method = new PostMethod(serviceUrl);
111
112 } else if (serviceType==HttpServiceType.TEST){
113 throw new UnsupportedOperationException("Haven't done this yet");
114 }
115 assert method!=null : "serviceType should be get, post or test";
116
117 if (log.isTraceEnabled()) {
118 log.trace("HttpServiceClient(String, HttpServiceType) - end");
119 }
120 }
121
122 /***
123 * Call the web server and return stuff.
124 * @return
125 * @throws HttpApplicationNetworkException
126 * @throws URIException
127 * @throws HttpApplicationWebServiceURLException
128 * @throws IOException
129 * @throws HttpException
130 */
131 public String call(final Map args) throws HttpApplicationNetworkException, HttpApplicationWebServiceURLException {
132 if (log.isTraceEnabled()) {
133 log.trace("call(Map args = " + args + ") - start");
134 }
135
136
137 NameValuePair[] argsArray = new NameValuePair[args.size()];
138 Set keys = args.keySet();
139 Iterator it = keys.iterator();
140 for (int i=0; it.hasNext(); ++i) {
141 Object key = it.next();
142 argsArray[i] = new NameValuePair((String) key, (String) args.get(key));
143 }
144
145
146
147
148 if (method instanceof PostMethod) {
149 ((PostMethod)method).setRequestBody(argsArray);
150 } else {
151 method.setQueryString(argsArray);
152 }
153
154 int statusCode = -1;
155
156 String results = null;
157 for (int attempt = 0; statusCode == -1 && attempt < MAX_ATTEMPTS; attempt++) {
158 try {
159
160 log.debug("Executing method: "+method);
161 statusCode = client.executeMethod(method);
162 results = method.getResponseBodyAsString();
163 log.debug("Method returned with results: "+results);
164 } catch (HttpRecoverableException e) {
165 log.warn("A recoverable error occured, retrying..."+attempt,e);
166 } catch (MalformedURLException e) {
167 log.error(e);
168 throw new HttpApplicationWebServiceURLException("A non-recoverable error occurred connecting to the web site", e);
169 } catch (IOException e) {
170 log.error(e);
171 throw new HttpApplicationNetworkException("A non-recoverable error occurred connecting to the web site", e);
172 } finally {
173
174
175 method.releaseConnection();
176
177 }
178 }
179
180
181 if (statusCode == -1) {
182 log.error("Failed to connect");
183 throw new HttpApplicationNetworkException("Failed to execute after "+MAX_ATTEMPTS+" tries");
184 } else if (statusCode == NOT_FOUND) {
185 try {
186 log.error("Web site not found");
187 throw new HttpApplicationWebServiceURLException("Page not found at " + method.getURI());
188 } catch (URIException e) {
189
190 log.error("Unknown URI");
191 }
192 }
193
194 assert results!=null;
195
196 if (log.isTraceEnabled()) {
197 log.trace("call(Map) - end - return value = " + results);
198 }
199 return results;
200 }
201
202 }
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229