2 * Copyright (C) 2007-2012 Mathieu Baudier
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org
.argeo
.slc
.server
.client
.impl
;
18 import java
.io
.IOException
;
19 import java
.io
.InputStreamReader
;
20 import java
.io
.OutputStreamWriter
;
21 import java
.io
.Reader
;
22 import java
.io
.Writer
;
23 import java
.net
.Authenticator
;
24 import java
.net
.HttpURLConnection
;
25 import java
.net
.PasswordAuthentication
;
27 import java
.net
.URLEncoder
;
30 import javax
.xml
.transform
.Source
;
31 import javax
.xml
.transform
.stream
.StreamResult
;
32 import javax
.xml
.transform
.stream
.StreamSource
;
34 import org
.apache
.commons
.io
.IOUtils
;
35 import org
.apache
.commons
.logging
.Log
;
36 import org
.apache
.commons
.logging
.LogFactory
;
37 import org
.argeo
.slc
.Condition
;
38 import org
.argeo
.slc
.SlcException
;
39 import org
.argeo
.slc
.server
.client
.HttpServicesClient
;
40 import org
.springframework
.oxm
.Marshaller
;
41 import org
.springframework
.oxm
.Unmarshaller
;
42 import org
.springframework
.util
.Assert
;
44 public abstract class AbstractHttpServicesClient
implements HttpServicesClient
{
45 private final static Log log
= LogFactory
46 .getLog(AbstractHttpServicesClient
.class);
49 private String password
;
51 private Unmarshaller unmarshaller
;
52 private Marshaller marshaller
;
53 private String baseUrl
;
54 private String encoding
= "UTF-8";
56 private Long retryPeriod
= 1000l;
57 private Long defaultTimeout
= 30 * 1000l;
60 if (user
!= null && password
!= null)
61 Authenticator
.setDefault(new Authenticator() {
62 protected PasswordAuthentication
getPasswordAuthentication() {
63 return new PasswordAuthentication(user
, password
69 @SuppressWarnings(value
= { "unchecked" })
70 public <T
> T
callService(String path
, Map
<String
, String
> parameters
) {
71 return (T
) callService(path
, parameters
, null);
74 @SuppressWarnings(value
= { "unchecked" })
75 public <T
> T
callService(String path
, Map
<String
, String
> parameters
,
78 return (T
) callServiceLowLevel(path
, parameters
, body
);
79 } catch (Exception e
) {
80 throw new SlcException("Cannot call service " + path
+ " on "
85 @SuppressWarnings(value
= { "unchecked" })
86 public <T
> T
callServiceSafe(String path
, Map
<String
, String
> parameters
,
87 Condition
<T
> condition
, Long timeout
) {
89 long begin
= System
.currentTimeMillis();
92 while (System
.currentTimeMillis() - begin
< timeout(timeout
)) {
94 obj
= callServiceLowLevel(path
, parameters
, null);
95 } catch (IOException e
) {
96 if (log
.isTraceEnabled())
97 log
.trace("Exception when calling service " + path
98 + " on " + baseUrl
, e
);
102 if (condition
== null)
105 if (condition
.check((T
) obj
))
111 Thread
.sleep(retryPeriod
);
112 } catch (InterruptedException e
) {
118 throw new SlcException(
123 + " did not return an answer after calling it safely for "
124 + timeout(timeout
) + " ms.");
126 } catch (Exception e
) {
127 throw new SlcException(
128 "Unexpected exception when safely calling service " + path
129 + " on " + baseUrl
, e
);
133 protected Object
callServiceLowLevel(String path
,
134 Map
<String
, String
> parameters
, Object body
) throws IOException
{
136 Assert
.notNull(baseUrl
, "base url");
137 HttpURLConnection connection
= null;
138 Writer writer
= null;
139 Reader reader
= null;
141 URL url
= createUrl(path
, parameters
);
142 connection
= (HttpURLConnection
) url
.openConnection();
145 connection
.setRequestMethod("POST");
146 connection
.setDoOutput(true);
147 connection
.setDoInput(true);
148 connection
.setUseCaches(false);
149 connection
.setAllowUserInteraction(false);
150 connection
.setRequestProperty("Content-type",
151 "text/xml; charset=" + encoding
);
154 // Establish the connection
155 connection
.connect();
158 writer
= new OutputStreamWriter(connection
.getOutputStream(),
160 StreamResult result
= new StreamResult(writer
);
161 marshaller
.marshal(body
, result
);
163 IOUtils
.closeQuietly(writer
);
167 reader
= new InputStreamReader(connection
.getInputStream(),
169 Source source
= new StreamSource(reader
);
170 Object obj
= unmarshaller
.unmarshal(source
);
173 IOUtils
.closeQuietly(reader
);
174 IOUtils
.closeQuietly(writer
);
175 if (connection
!= null) {
176 connection
.disconnect();
181 protected URL
createUrl(String service
, Map
<String
, String
> parameters
) {
182 // URL encoded with UTF-8, as recommended by W3C
183 final String urlEncoding
= "UTF-8";
185 StringBuffer buf
= new StringBuffer(baseUrl
+ service
);
187 if (parameters
!= null && parameters
.size() != 0) {
189 boolean first
= true;
190 for (String key
: parameters
.keySet()) {
191 String value
= parameters
.get(key
);
197 String keyEncoded
= URLEncoder
.encode(key
, urlEncoding
);
198 String valueEncoded
= URLEncoder
.encode(value
,
200 buf
.append(keyEncoded
).append('=').append(valueEncoded
);
205 return new URL(buf
.toString());
206 } catch (Exception e
) {
207 throw new SlcException("Cannot create URL: " + buf
, e
);
211 public Long
timeout(Long timeout
) {
213 timeout
= getDefaultTimeout();
217 public void setUnmarshaller(Unmarshaller unmarshaller
) {
218 this.unmarshaller
= unmarshaller
;
221 public void setBaseUrl(String baseUrl
) {
222 this.baseUrl
= baseUrl
;
225 public Long
getRetryPeriod() {
229 /** Retry period in ms when accessing service safely. Default is 1000 ms. */
230 public void setRetryPeriod(Long retryPeriod
) {
231 this.retryPeriod
= retryPeriod
;
234 public void setMarshaller(Marshaller marshaller
) {
235 this.marshaller
= marshaller
;
238 /** Default is UTF-8. */
239 public void setEncoding(String encoding
) {
240 this.encoding
= encoding
;
243 /** Default is 30s */
244 public void setDefaultTimeout(Long defaultTimeout
) {
245 this.defaultTimeout
= defaultTimeout
;
248 public Long
getDefaultTimeout() {
249 return defaultTimeout
;
252 public void setUser(String user
) {
256 public void setPassword(String password
) {
257 this.password
= password
;