Statistics
| Revision:

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
}