svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.plugin / org.gvsig.downloader / org.gvsig.downloader.lib / org.gvsig.downloader.lib.impl / src / main / java / org / gvsig / downloader / lib / impl / SEAuthDownloaderTask.java @ 47845
History | View | Annotate | Download (13.7 KB)
1 | 47821 | jjdelcerro | package org.gvsig.downloader.lib.impl; |
---|---|---|---|
2 | 41528 | jjdelcerro | |
3 | import java.io.File; |
||
4 | 47821 | jjdelcerro | import java.io.IOException; |
5 | import java.io.InputStream; |
||
6 | 47826 | fdiaz | import java.net.SocketTimeoutException; |
7 | 47845 | fdiaz | import java.net.URI; |
8 | import java.net.URISyntaxException; |
||
9 | 41528 | jjdelcerro | import java.net.URL; |
10 | 47821 | jjdelcerro | import java.util.Objects; |
11 | 47824 | fdiaz | import java.util.concurrent.Executor; |
12 | 47821 | jjdelcerro | import org.apache.commons.io.IOUtils; |
13 | import org.apache.commons.lang3.StringUtils; |
||
14 | import org.apache.http.Header; |
||
15 | import org.apache.http.HttpEntity; |
||
16 | import org.apache.http.HttpResponse; |
||
17 | import org.apache.http.auth.AuthenticationException; |
||
18 | import org.apache.http.client.ClientProtocolException; |
||
19 | import org.apache.http.client.ResponseHandler; |
||
20 | 47826 | fdiaz | import org.apache.http.client.config.RequestConfig; |
21 | 47821 | jjdelcerro | import org.apache.http.client.methods.HttpDelete; |
22 | import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; |
||
23 | import org.apache.http.client.methods.HttpGet; |
||
24 | import org.apache.http.client.methods.HttpPost; |
||
25 | import org.apache.http.client.methods.HttpPut; |
||
26 | import org.apache.http.client.methods.HttpRequestBase; |
||
27 | import org.apache.http.client.methods.HttpUriRequest; |
||
28 | 47826 | fdiaz | import org.apache.http.conn.ConnectTimeoutException; |
29 | 47821 | jjdelcerro | import org.apache.http.entity.ContentType; |
30 | import org.apache.http.entity.StringEntity; |
||
31 | import org.apache.http.impl.client.CloseableHttpClient; |
||
32 | import org.apache.http.impl.client.HttpClientBuilder; |
||
33 | import org.gvsig.compat.se.net.downloader.se.AbstractSEDownloaderTask; |
||
34 | 47824 | fdiaz | import org.gvsig.compat.se.net.downloader.se.SEDownloader; |
35 | 47821 | jjdelcerro | import org.gvsig.downloader.DownloaderAuthenticationConfig; |
36 | import org.gvsig.downloader.DownloaderAuthenticationRequester; |
||
37 | import org.gvsig.downloader.DownloaderCredentials; |
||
38 | 47840 | jjdelcerro | import org.gvsig.downloader.DownloaderManager; |
39 | 47843 | fdiaz | import org.gvsig.downloader.IOExceptionWithStatus; |
40 | 47845 | fdiaz | import org.slf4j.Logger; |
41 | import org.slf4j.LoggerFactory; |
||
42 | 41528 | jjdelcerro | |
43 | 47821 | jjdelcerro | @SuppressWarnings("UseSpecificCatch") |
44 | final class SEAuthDownloaderTask |
||
45 | extends AbstractSEDownloaderTask
|
||
46 | 47845 | fdiaz | implements Runnable |
47 | { |
||
48 | 41528 | jjdelcerro | |
49 | 47845 | fdiaz | private static Logger LOGGER = LoggerFactory.getLogger(SEAuthDownloaderTask.class); |
50 | |||
51 | 47821 | jjdelcerro | private class DownloaderResponseHandler implements ResponseHandler<Object> { |
52 | |||
53 | private int status; |
||
54 | private HttpResponse response;
|
||
55 | 41528 | jjdelcerro | |
56 | 47821 | jjdelcerro | public DownloaderResponseHandler() {
|
57 | 47826 | fdiaz | this.status = 0; |
58 | 47821 | jjdelcerro | } |
59 | |||
60 | @Override
|
||
61 | public Object handleResponse(HttpResponse response) throws ClientProtocolException, IOException { |
||
62 | this.status=response.getStatusLine().getStatusCode();
|
||
63 | this.response = response;
|
||
64 | try {
|
||
65 | HttpEntity entity = response.getEntity(); |
||
66 | 47826 | fdiaz | if(entity == null) { |
67 | 47821 | jjdelcerro | download(null);
|
68 | } else {
|
||
69 | InputStream content = entity.getContent();
|
||
70 | download(content); |
||
71 | } |
||
72 | |||
73 | 47826 | fdiaz | } catch (IOExceptionWithStatus ex) {
|
74 | 47821 | jjdelcerro | throw ex;
|
75 | } catch (Exception ex) { |
||
76 | 47826 | fdiaz | throw new IOExceptionWithStatus(this.status, ex.getLocalizedMessage(), ex); |
77 | 47821 | jjdelcerro | } |
78 | return null; |
||
79 | } |
||
80 | |||
81 | 47833 | fdiaz | public int getStatus() { |
82 | 47821 | jjdelcerro | return this.status; |
83 | } |
||
84 | 47833 | fdiaz | |
85 | public String getRedirectionLocation() { |
||
86 | try {
|
||
87 | Header header = this.response.getFirstHeader("Location"); |
||
88 | if(header != null) { |
||
89 | return header.getValue();
|
||
90 | } |
||
91 | } catch (Exception ex) { |
||
92 | LOGGER.debug("Can't get redirection location", ex);
|
||
93 | } |
||
94 | return null; |
||
95 | } |
||
96 | 41528 | jjdelcerro | } |
97 | |||
98 | 47824 | fdiaz | public SEAuthDownloaderTask(SEDownloader downloader, URL url, String data, File dstFile, Object groupID) { |
99 | 47821 | jjdelcerro | super(downloader, url, data, dstFile, groupID);
|
100 | 42140 | jjdelcerro | } |
101 | |||
102 | 47840 | jjdelcerro | public SEAuthDownloaderTask(SEDownloader downloader, URL url, String method, ContentType contenttype, String data, File dstFile, Object groupID) { |
103 | super(downloader, url, method, contenttype, data, dstFile, groupID);
|
||
104 | } |
||
105 | |||
106 | 47821 | jjdelcerro | private DownloaderManagerImpl getDownloader() {
|
107 | return (DownloaderManagerImpl) this.downloader; |
||
108 | 42140 | jjdelcerro | } |
109 | 47821 | jjdelcerro | |
110 | 47833 | fdiaz | private DownloaderCredentials getCredentials(URL url) { |
111 | return this.getDownloader().getCredentials(url); |
||
112 | 47821 | jjdelcerro | } |
113 | |||
114 | private void addOrReplaceCredentials(DownloaderCredentials credentials) { |
||
115 | this.getDownloader().addOrReplaceCredentials(credentials);
|
||
116 | } |
||
117 | |||
118 | 47833 | fdiaz | private DownloaderAuthenticationConfig getServiceAuthorizationConfig(URL url) { |
119 | return this.getDownloader().getAuthenticationConfigurationService(url.toString()); |
||
120 | 47821 | jjdelcerro | } |
121 | |||
122 | 47833 | fdiaz | private void authorize(URL url) { |
123 | 47821 | jjdelcerro | try {
|
124 | LOGGER.info("AUTHORIZATION REQUIRED");
|
||
125 | 47833 | fdiaz | DownloaderAuthenticationConfig config = this.getServiceAuthorizationConfig(url);
|
126 | 47821 | jjdelcerro | if( config == null ) { |
127 | 47833 | fdiaz | config = this.getDownloader().requestAutenticationConfig(url);
|
128 | 47821 | jjdelcerro | if( config == null ) { |
129 | 47833 | fdiaz | throw new AuthenticationException("Not service authentication configured for url '"+url+"'."); |
130 | 47821 | jjdelcerro | } |
131 | } |
||
132 | DownloaderAuthenticationRequester authorizationRequester = config.create(); |
||
133 | if( authorizationRequester == null ) { |
||
134 | 47833 | fdiaz | throw new AuthenticationException("Can't configure service authentication for url '"+url+"'."); |
135 | 47821 | jjdelcerro | } |
136 | LOGGER.info("AUTHORIZATION REQUESTER TYPE: "+authorizationRequester.getProviderName());
|
||
137 | 47824 | fdiaz | if( !authorizationRequester.requestAuthorization(this.getExecutorUI()) ) { |
138 | 47821 | jjdelcerro | return;
|
139 | } |
||
140 | DownloaderCredentials credentials = authorizationRequester.getCredentials(); |
||
141 | addOrReplaceCredentials(credentials); |
||
142 | LOGGER.info("CREDENTIALS: "+credentials.toString());
|
||
143 | } catch (Exception ex) { |
||
144 | LOGGER.warn("Can't authorize", ex);
|
||
145 | } |
||
146 | } |
||
147 | |||
148 | private DownloaderResponseHandler executeRequest(HttpUriRequest request) throws IOException { |
||
149 | 42140 | jjdelcerro | |
150 | 47826 | fdiaz | int timeout = getTimeout();
|
151 | RequestConfig requestConfig = RequestConfig.custom() |
||
152 | .setConnectTimeout(timeout) |
||
153 | .setConnectionRequestTimeout(timeout) |
||
154 | .setSocketTimeout(timeout) |
||
155 | .build(); |
||
156 | 47833 | fdiaz | URL theUrl = request.getURI().toURL();
|
157 | 47826 | fdiaz | CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build(); |
158 | 47833 | fdiaz | DownloaderCredentials credentials = this.getCredentials(theUrl);
|
159 | 47837 | fdiaz | if (credentials == null || credentials.isAuthorizationTokenExpired()) { |
160 | 47833 | fdiaz | DownloaderAuthenticationConfig config = this.getServiceAuthorizationConfig(theUrl);
|
161 | 47837 | fdiaz | if( config != null ) { |
162 | 47821 | jjdelcerro | DownloaderAuthenticationRequester authorizationRequester = config.create(); |
163 | if( authorizationRequester!=null ) { |
||
164 | 47824 | fdiaz | if( authorizationRequester.requestAuthorization(this.getExecutorUI()) ) { |
165 | 47821 | jjdelcerro | credentials = authorizationRequester.getCredentials(); |
166 | addOrReplaceCredentials(credentials); |
||
167 | request.addHeader("Authorization", credentials.getAuthorizationToken());
|
||
168 | } |
||
169 | } |
||
170 | } |
||
171 | } else {
|
||
172 | request.addHeader("Authorization", credentials.getAuthorizationToken());
|
||
173 | } |
||
174 | DownloaderResponseHandler responseHandler = new DownloaderResponseHandler();
|
||
175 | |||
176 | LOGGER.info("REQUEST "+request.getMethod()+" "+request.getURI().toString()); |
||
177 | 47826 | fdiaz | LOGGER.info("TIMEOUT "+timeout);
|
178 | 47821 | jjdelcerro | for (Header header : request.getAllHeaders()) {
|
179 | LOGGER.info(header.getName()+": "+header.getValue());
|
||
180 | } |
||
181 | if( request instanceof HttpEntityEnclosingRequestBase ) { |
||
182 | InputStream content = ((HttpEntityEnclosingRequestBase) request).getEntity().getContent();
|
||
183 | LOGGER.info("BODY data "+(StringUtils.join(IOUtils.readLines(content,"utf-8"),"\n"))); |
||
184 | } |
||
185 | 47826 | fdiaz | LOGGER.info("DOWNLOAD TO "+Objects.toString(dstFile));
|
186 | try {
|
||
187 | httpClient.execute(request,responseHandler); |
||
188 | } catch (SocketTimeoutException|ConnectTimeoutException ex) { |
||
189 | LOGGER.info("RESPONSE TIMEOUT");
|
||
190 | throw ex;
|
||
191 | } catch (Exception ex) { |
||
192 | LOGGER.info("RESPONSE ERROR "+ex.getLocalizedMessage());
|
||
193 | throw ex;
|
||
194 | } |
||
195 | 47833 | fdiaz | int status =responseHandler.getStatus();
|
196 | if(status == 307 || status == 308){ |
||
197 | LOGGER.info("RESPONSE LOCATION "+Objects.toString(responseHandler.getRedirectionLocation()));
|
||
198 | } |
||
199 | LOGGER.info("RESPONSE CODE "+status);
|
||
200 | 47821 | jjdelcerro | |
201 | return responseHandler;
|
||
202 | } |
||
203 | |||
204 | 47845 | fdiaz | private URI urlToUri(URL url) throws URISyntaxException{ |
205 | try {
|
||
206 | URI uri = url.toURI();
|
||
207 | return uri;
|
||
208 | } catch (URISyntaxException ex) { |
||
209 | String s = url.toExternalForm();
|
||
210 | //?apa hasta que se arregle la construcci?n de URL de tiles de WMTS
|
||
211 | // s = StringUtils.replace(s, "{", "%7B");
|
||
212 | // s = StringUtils.replace(s, "}", "%7D");
|
||
213 | return new URI(s); |
||
214 | } |
||
215 | } |
||
216 | 47821 | jjdelcerro | |
217 | private File send(String method, ContentType contentType, String data) throws IOExceptionWithStatus { |
||
218 | int status = 500; |
||
219 | 47833 | fdiaz | URL theUrl = url;
|
220 | 47821 | jjdelcerro | try {
|
221 | 47845 | fdiaz | URI theUri = urlToUri(url);
|
222 | 47821 | jjdelcerro | int numretries = 3; |
223 | for (int retries = 0; retries < numretries; retries++) { |
||
224 | 47840 | jjdelcerro | HttpRequestBase request; |
225 | 47821 | jjdelcerro | switch (method.toUpperCase()) {
|
226 | 47840 | jjdelcerro | case DownloaderManager.METHOD_DELETE:
|
227 | 47845 | fdiaz | request = new HttpDelete(theUri);
|
228 | 47840 | jjdelcerro | break;
|
229 | case DownloaderManager.METHOD_PUT:
|
||
230 | 47845 | fdiaz | request = new HttpPut(theUri);
|
231 | 47843 | fdiaz | request.setHeader("Content-type", contentType.toString());
|
232 | 47840 | jjdelcerro | ((HttpPut)request).setEntity(new StringEntity(data, contentType));
|
233 | 47821 | jjdelcerro | break;
|
234 | 47840 | jjdelcerro | case DownloaderManager.METHOD_POST:
|
235 | 47845 | fdiaz | request = new HttpPost(theUri);
|
236 | 47821 | jjdelcerro | request.setHeader("SOAPAction", "post"); |
237 | 47843 | fdiaz | request.setHeader("Content-type", contentType.toString());
|
238 | 47840 | jjdelcerro | ((HttpPost)request).setEntity(new StringEntity(data, contentType));
|
239 | 47821 | jjdelcerro | break;
|
240 | 47840 | jjdelcerro | case DownloaderManager.METHOD_GET:
|
241 | default:
|
||
242 | 47845 | fdiaz | request = new HttpGet(theUri);
|
243 | 47840 | jjdelcerro | break;
|
244 | 47821 | jjdelcerro | } |
245 | // request.setHeader("User-Agent","Mozilla/5.0 (gvSIG) like Gecko");
|
||
246 | request.setHeader("User-Agent","gvSIG-desktop"); |
||
247 | request.setHeader("Referer","http://www.gvsig.com"); |
||
248 | DownloaderResponseHandler responseHandler = executeRequest(request); |
||
249 | status = responseHandler.getStatus(); |
||
250 | if(status >= 200 && status < 300) { |
||
251 | //2xx success
|
||
252 | return this.dstFile; |
||
253 | |||
254 | 47833 | fdiaz | } else if(status == 307 || status == 308) { |
255 | String redirection = responseHandler.getRedirectionLocation();
|
||
256 | if(StringUtils.isBlank(redirection)) {
|
||
257 | throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' HTTPStatus = "+status+" redirect to blank URL."); |
||
258 | } |
||
259 | try {
|
||
260 | theUrl = new URL(redirection); |
||
261 | } catch (Exception ex) { |
||
262 | throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' HTTPStatus = "+status+" redirect to invalid URL "+redirection); |
||
263 | } |
||
264 | 47821 | jjdelcerro | } else if(status >= 300 && status < 400) { |
265 | // 3xx redirection
|
||
266 | 47833 | fdiaz | throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' HTTPStatus = "+status); |
267 | 47821 | jjdelcerro | } else if(status == 401 || status == 403) { |
268 | // "401 Unauthorized" indicates that the request lacks valid authentication credentials
|
||
269 | // "403 Forbidden" the client doesn't have permission to access the requested resource
|
||
270 | // https://www.permit.io/blog/401-vs-403-error-whats-the-difference
|
||
271 | if( retries < numretries-1 ) { |
||
272 | 47833 | fdiaz | authorize(theUrl); |
273 | 47821 | jjdelcerro | } |
274 | } else if(status >= 400 && status < 500) { |
||
275 | // 4xx client errors
|
||
276 | 47833 | fdiaz | throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' HTTPStatus = "+status); |
277 | 47821 | jjdelcerro | } else if(status >= 500 && status < 600) { |
278 | // 5xx server errors
|
||
279 | 47833 | fdiaz | throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' HTTPStatus = "+status); |
280 | 47821 | jjdelcerro | } else {
|
281 | //Unknown
|
||
282 | 47833 | fdiaz | throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' HTTPStatus = "+status); |
283 | 47821 | jjdelcerro | } |
284 | } |
||
285 | 47833 | fdiaz | throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' too many retries, last status " + status); |
286 | 47821 | jjdelcerro | |
287 | } catch (IOExceptionWithStatus ex) {
|
||
288 | throw ex;
|
||
289 | } catch (Throwable ex) { |
||
290 | 47833 | fdiaz | throw new IOExceptionWithStatus(status, "Can't call method "+method+" "+Objects.toString(theUrl)+"' last status " + status, ex); |
291 | 47821 | jjdelcerro | } |
292 | } |
||
293 | 42140 | jjdelcerro | |
294 | 47821 | jjdelcerro | |
295 | |||
296 | @Override
|
||
297 | 41528 | jjdelcerro | public void run() { |
298 | 47821 | jjdelcerro | try {
|
299 | 47840 | jjdelcerro | send(this.method, this.contenttype, this.data); |
300 | 47821 | jjdelcerro | postdownload(); |
301 | } catch (Exception e) { |
||
302 | exception(e); |
||
303 | } |
||
304 | 41528 | jjdelcerro | } |
305 | |||
306 | 47824 | fdiaz | private Executor getExecutorUI() { |
307 | 47828 | jjdelcerro | // return this.downloader.getExecutorUI();
|
308 | return null; |
||
309 | 47824 | fdiaz | } |
310 | 47821 | jjdelcerro | } |