]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.launcher/src/main/java/org/argeo/slc/server/client/impl/AbstractHttpServicesClient.java
Restructure HTTP service client
[gpl/argeo-slc.git] / runtime / org.argeo.slc.launcher / src / main / java / org / argeo / slc / server / client / impl / AbstractHttpServicesClient.java
1 package org.argeo.slc.server.client.impl;
2
3 import java.io.IOException;
4 import java.io.InputStreamReader;
5 import java.io.OutputStreamWriter;
6 import java.io.Reader;
7 import java.io.Writer;
8 import java.net.HttpURLConnection;
9 import java.net.URL;
10 import java.net.URLEncoder;
11 import java.util.Map;
12
13 import javax.xml.transform.Source;
14 import javax.xml.transform.stream.StreamResult;
15 import javax.xml.transform.stream.StreamSource;
16
17 import org.apache.commons.io.IOUtils;
18 import org.apache.commons.logging.Log;
19 import org.apache.commons.logging.LogFactory;
20 import org.argeo.slc.Condition;
21 import org.argeo.slc.SlcException;
22 import org.argeo.slc.server.client.HttpServicesClient;
23 import org.springframework.oxm.Marshaller;
24 import org.springframework.oxm.Unmarshaller;
25 import org.springframework.util.Assert;
26
27 public abstract class AbstractHttpServicesClient implements HttpServicesClient {
28 private final static Log log = LogFactory
29 .getLog(AbstractHttpServicesClient.class);
30 private Unmarshaller unmarshaller;
31 private Marshaller marshaller;
32 private String baseUrl;
33 private String encoding = "UTF-8";
34
35 private Long retryPeriod = 1000l;
36 private Long defaultTimeout = 30 * 1000l;
37
38 @SuppressWarnings(value = { "unchecked" })
39 public <T> T callService(String path, Map<String, String> parameters) {
40 return (T)callService(path, parameters, null);
41 }
42
43 @SuppressWarnings(value = { "unchecked" })
44 public <T> T callService(String path, Map<String, String> parameters,
45 Object body) {
46 try {
47 return (T) callServiceLowLevel(path, parameters, body);
48 } catch (Exception e) {
49 throw new SlcException("Cannot call service " + path + " on "
50 + baseUrl, e);
51 }
52 }
53
54 @SuppressWarnings(value = { "unchecked" })
55 public <T> T callServiceSafe(String path, Map<String, String> parameters,
56 Condition<T> condition, Long timeout) {
57
58 long begin = System.currentTimeMillis();
59 try {
60 Object obj = null;
61 while (System.currentTimeMillis() - begin < timeout(timeout)) {
62 try {
63 obj = callServiceLowLevel(path, parameters, null);
64 } catch (IOException e) {
65 if (log.isTraceEnabled())
66 log.trace("Exception when calling service " + path
67 + " on " + baseUrl, e);
68 }
69
70 if (obj != null) {
71 if (condition == null)
72 break;
73 else {
74 if (condition.check((T) obj))
75 break;
76 }
77 }
78 // wait a bit
79 try {
80 Thread.sleep(retryPeriod);
81 } catch (InterruptedException e) {
82 // silent
83 }
84 }
85
86 if (obj == null)
87 throw new SlcException(
88 "Service "
89 + path
90 + " on "
91 + baseUrl
92 + " did not return an answer after calling it safely for "
93 + timeout(timeout) + " ms.");
94 return (T) obj;
95 } catch (Exception e) {
96 throw new SlcException(
97 "Unexpected exception when safely calling service " + path
98 + " on " + baseUrl, e);
99 }
100 }
101
102 protected Object callServiceLowLevel(String path,
103 Map<String, String> parameters, Object body) throws IOException {
104 Assert.notNull(baseUrl, "base url");
105 HttpURLConnection connection = null;
106 Writer writer = null;
107 Reader reader = null;
108 try {
109 URL url = createUrl(path, parameters);
110 connection = (HttpURLConnection) url.openConnection();
111
112 if (body != null) {
113 connection.setRequestMethod("POST");
114 connection.setDoOutput(true);
115 connection.setDoInput(true);
116 connection.setUseCaches(false);
117 connection.setAllowUserInteraction(false);
118 connection.setRequestProperty("Content-type",
119 "text/xml; charset=" + encoding);
120 }
121
122 // Establish the connection
123 connection.connect();
124
125 if (body != null) {
126 writer = new OutputStreamWriter(connection.getOutputStream(),
127 encoding);
128 StreamResult result = new StreamResult(writer);
129 marshaller.marshal(body, result);
130 writer.flush();
131 IOUtils.closeQuietly(writer);
132 }
133
134 // Read answer
135 reader = new InputStreamReader(connection.getInputStream(),
136 encoding);
137 Source source = new StreamSource(reader);
138 Object obj = unmarshaller.unmarshal(source);
139 return obj;
140 } finally {
141 IOUtils.closeQuietly(reader);
142 IOUtils.closeQuietly(writer);
143 if (connection != null) {
144 connection.disconnect();
145 }
146 }
147 }
148
149 protected URL createUrl(String service, Map<String, String> parameters) {
150 // URL encoded with UTF-8, as recommended by W3C
151 final String urlEncoding = "UTF-8";
152
153 StringBuffer buf = new StringBuffer(baseUrl + service);
154 try {
155 if (parameters != null && parameters.size() != 0) {
156 buf.append('?');
157 boolean first = true;
158 for (String key : parameters.keySet()) {
159 String value = parameters.get(key);
160 if (value != null) {
161 if (first)
162 first = false;
163 else
164 buf.append('&');
165 String keyEncoded = URLEncoder.encode(key, urlEncoding);
166 String valueEncoded = URLEncoder.encode(value,
167 urlEncoding);
168 buf.append(keyEncoded).append('=').append(valueEncoded);
169 }
170 }
171 }
172
173 return new URL(buf.toString());
174 } catch (Exception e) {
175 throw new SlcException("Cannot create URL: " + buf, e);
176 }
177 }
178
179 public Long timeout(Long timeout) {
180 if (timeout == null)
181 timeout = getDefaultTimeout();
182 return timeout;
183 }
184
185 public void setUnmarshaller(Unmarshaller unmarshaller) {
186 this.unmarshaller = unmarshaller;
187 }
188
189 public void setBaseUrl(String baseUrl) {
190 this.baseUrl = baseUrl;
191 }
192
193 public Long getRetryPeriod() {
194 return retryPeriod;
195 }
196
197 /** Retry period in ms when accessing service safely. Default is 1000 ms. */
198 public void setRetryPeriod(Long retryPeriod) {
199 this.retryPeriod = retryPeriod;
200 }
201
202 public void setMarshaller(Marshaller marshaller) {
203 this.marshaller = marshaller;
204 }
205
206 /** Default is UTF-8. */
207 public void setEncoding(String encoding) {
208 this.encoding = encoding;
209 }
210
211 /** Default is 30s */
212 public void setDefaultTimeout(Long defaultTimeout) {
213 this.defaultTimeout = defaultTimeout;
214 }
215
216 public Long getDefaultTimeout() {
217 return defaultTimeout;
218 }
219
220 }