1 /*
2 * Copyright 2007-2012 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.springbyexample.httpclient;
18
19 import java.io.ByteArrayOutputStream;
20 import java.io.IOException;
21 import java.util.Map;
22
23 import javax.xml.transform.stream.StreamResult;
24 import javax.xml.transform.stream.StreamSource;
25
26 import org.apache.commons.httpclient.HttpException;
27 import org.apache.commons.httpclient.HttpMethod;
28 import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
29 import org.apache.commons.httpclient.methods.PostMethod;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32 import org.springframework.beans.factory.InitializingBean;
33 import org.springframework.oxm.Marshaller;
34 import org.springframework.oxm.MarshallingFailureException;
35 import org.springframework.oxm.Unmarshaller;
36 import org.springframework.stereotype.Component;
37 import org.springframework.util.Assert;
38
39 /**
40 * Template for easier use of <code>HttpClient</code> and
41 * also uses Spring Web Services OXM framework to marshall/unmarshall
42 * XML from requests and responses.
43 *
44 * @author David Winterfeldt
45 */
46 @Component
47 public class HttpClientOxmTemplate<T> extends AbstractHttpClientTemplate<T>
48 implements InitializingBean {
49
50 final Logger logger = LoggerFactory.getLogger(HttpClientOxmTemplate.class);
51
52 protected Marshaller marshaller = null;
53 protected Unmarshaller unmarshaller = null;
54
55 /**
56 * Constructor.
57 */
58 public HttpClientOxmTemplate() {}
59
60 /**
61 * Constructor.
62 *
63 * @param defaultUri Default uri.
64 */
65 public HttpClientOxmTemplate(String defaultUri) {
66 super(defaultUri, false);
67 }
68
69 /**
70 * Constructor.
71 *
72 * @param defaultUri Default uri.
73 * @param marshaller Marshaller to use for marshalling requests.
74 * @param unmarshaller Unmarshaller to use for unmarshalling requests.
75 */
76 public HttpClientOxmTemplate(String defaultUri,
77 Marshaller marshaller, Unmarshaller unmarshaller) {
78 this(defaultUri);
79
80 this.marshaller = marshaller;
81 this.unmarshaller = unmarshaller;
82 }
83
84 /**
85 * Constructor.
86 *
87 * @param defaultUri Default uri.
88 * @param marshaller Marshaller to use for marshalling requests.
89 * @param unmarshaller Unmarshaller to use for unmarshalling requests.
90 * @param init Whether or not to initialize the bean.
91 */
92 public HttpClientOxmTemplate(String defaultUri,
93 Marshaller marshaller, Unmarshaller unmarshaller,
94 boolean init) {
95 this(defaultUri, marshaller, unmarshaller);
96
97 if (init) {
98 try {
99 afterPropertiesSet();
100 } catch(Exception e) {
101 throw new HttpAccessException(e.getMessage(), e);
102 }
103 }
104 }
105
106 /**
107 * Gets marshaller.
108 */
109 public Marshaller getMarshaller() {
110 return marshaller;
111 }
112
113 /**
114 * Sets marshaller.
115 */
116 public void setMarshaller(Marshaller marshaller) {
117 this.marshaller = marshaller;
118 }
119
120 /**
121 * Gets unmarshaller.
122 */
123 public Unmarshaller getUnmarshaller() {
124 return unmarshaller;
125 }
126
127 /**
128 * Sets unmarshaller.
129 */
130 public void setUnmarshaller(Unmarshaller unmarshaller) {
131 this.unmarshaller = unmarshaller;
132 }
133
134 /**
135 * Implementation of <code>InitializingBean</code>
136 * that initializes the <code>HttpClient</code> if it is <code>null</code>
137 * and also sets the connection manager to <code>MultiThreadedHttpConnectionManager</code>
138 * if it is <code>null</code> while initializing the <code>HttpClient</code>.
139 */
140 public void afterPropertiesSet() throws Exception {
141 Assert.notNull(marshaller);
142 Assert.notNull(unmarshaller);
143
144 super.afterPropertiesSet();
145 }
146
147 /**
148 * Execute post method.
149 *
150 * @param requestPayload Request data to post after marshalling.
151 * The <code>Marshaller</code> should be able to
152 * process this instance.
153 */
154 public void executePostMethod(T requestPayload) {
155 executePostMethod(defaultUri, requestPayload, null, null);
156 }
157
158 /**
159 * Execute post method.
160 *
161 * @param requestPayload Request data to post after marshalling.
162 * The <code>Marshaller</code> should be able to
163 * process this instance.
164 * @param callback Callback with HTTP method's response.
165 */
166 public void executePostMethod(T requestPayload, ResponseCallback<?> callback) {
167 executePostMethod(defaultUri, requestPayload, null, callback);
168 }
169
170 /**
171 * Execute post method.
172 *
173 * @param requestPayload Request data to post after marshalling.
174 * The <code>Marshaller</code> should be able to
175 * process this instance.
176 * @param hParams Parameters for the HTTP post.
177 */
178 public void executePostMethod(T requestPayload, Map<String, String> hParams) {
179 executePostMethod(requestPayload, hParams, null);
180 }
181
182 /**
183 * Execute post method.
184 *
185 * @param requestPayload Request data to post after marshalling.
186 * The <code>Marshaller</code> should be able to
187 * process this instance.
188 * @param hParams Parameters for the HTTP post.
189 * @param callback Callback with HTTP method's response.
190 */
191 public void executePostMethod(T requestPayload, Map<String, String> hParams,
192 ResponseCallback<?> callback) {
193 executePostMethod(defaultUri, requestPayload, hParams, callback);
194 }
195
196 /**
197 * Execute post method.
198 *
199 * @param uri URI to use when processing this HTTP request instead
200 * of using the default URI.
201 * @param requestPayload Request data to post after marshalling.
202 * The <code>Marshaller</code> should be able to
203 * process this instance.
204 * @param hParams Parameters for the HTTP post.
205 * @param callback Callback with HTTP method's response.
206 */
207 public void executePostMethod(String uri,
208 T requestPayload, Map<String, String> hParams,
209 ResponseCallback<?> callback) {
210 PostMethod post = new PostMethod(uri);
211
212 if (requestPayload != null) {
213 ByteArrayOutputStream out = new ByteArrayOutputStream();
214
215 try {
216 marshaller.marshal(requestPayload, new StreamResult(out));
217 } catch (IOException e) {
218 throw new MarshallingFailureException(e.getMessage(), e);
219 }
220
221 post.setRequestEntity(new ByteArrayRequestEntity(out.toByteArray()));
222 }
223
224 processHttpMethodParams(post, hParams);
225
226 processHttpMethod(post, callback);
227 }
228
229 /**
230 * Processes <code>HttpMethod</code> by executing the method,
231 * validating the response, and calling the callback.
232 *
233 * @param httpMethod <code>HttpMethod</code> to process.
234 * @param callback Callback with HTTP method's response.
235 */
236 @SuppressWarnings("unchecked")
237 protected void processHttpMethod(HttpMethod httpMethod, ResponseCallback callback) {
238 try {
239 client.executeMethod(httpMethod);
240
241 validateResponse(httpMethod);
242
243 if (callback != null) {
244 Object value = unmarshaller.unmarshal(new StreamSource(httpMethod.getResponseBodyAsStream()));
245
246 callback.doWithResponse((T)value);
247 }
248 } catch (HttpException e) {
249 throw new HttpAccessException(e.getMessage(), e, httpMethod.getStatusCode());
250 } catch (IOException e) {
251 throw new HttpAccessException(e.getMessage(), e);
252 } finally {
253 httpMethod.releaseConnection();
254 }
255 }
256
257 }