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