Statistics
| Revision:

root / branches / v2_0_0_prep / libraries / libCompat / src / org / gvsig / compat / se / net / SEDownloader.java @ 34026

History | View | Annotate | Download (15 KB)

1
package org.gvsig.compat.se.net;
2
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
3
 *
4
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
19
 *
20
 * For more information, contact:
21
 *
22
 *  Generalitat Valenciana
23
 *   Conselleria d'Infraestructures i Transport
24
 *   Av. Blasco Ib??ez, 50
25
 *   46010 VALENCIA
26
 *   SPAIN
27
 *
28
 *      +34 963862235
29
 *   gvsig@gva.es
30
 *      www.gvsig.gva.es
31
 *
32
 *    or
33
 *
34
 *   IVER T.I. S.A
35
 *   Salamanca 50
36
 *   46005 Valencia
37
 *   Spain
38
 *
39
 *   +34 963163400
40
 *   dac@iver.es
41
 */
42

    
43
import java.io.BufferedOutputStream;
44
import java.io.DataInputStream;
45
import java.io.DataOutputStream;
46
import java.io.File;
47
import java.io.FileNotFoundException;
48
import java.io.FileOutputStream;
49
import java.io.IOException;
50
import java.io.OutputStreamWriter;
51
import java.net.ConnectException;
52
import java.net.HttpURLConnection;
53
import java.net.URL;
54
import java.net.UnknownHostException;
55
import java.security.KeyManagementException;
56
import java.security.NoSuchAlgorithmException;
57
import java.util.Hashtable;
58

    
59
import javax.net.ssl.HttpsURLConnection;
60
import javax.net.ssl.SSLContext;
61
import javax.net.ssl.TrustManager;
62
import javax.net.ssl.X509TrustManager;
63

    
64
import org.gvsig.compat.net.ICancellable;
65

    
66

    
67
/**
68
 * Clase con m?todos de utilidad en el protocolo WMS
69
 *
70
 * @authors Laura D?az, jaume dominguez faus
71
 */
72
public class SEDownloader implements org.gvsig.compat.net.Downloader{
73
    String characters;
74
        boolean canceled;
75
        final long latency = 500;
76
                
77
        /**
78
         * Used to cancel a group of files
79
         * <b>key</b>: Group id, <b>value</b>: Boolean (true if
80
         * the group has to be canceled. Otherwise it is
81
         * false)
82
         */
83
        Hashtable canceledGroup = new Hashtable();
84
        /**
85
         * <b>key</b>: URL, <b>value</b>: path to the downloaded file.
86
         */
87
        Hashtable downloadedFiles;
88
        Exception downloadException;
89
        final String tempDirectoryPath = System.getProperty("java.io.tmpdir")+"/tmp-andami";
90
    
91
        public SEDownloader() {
92
        super();  
93
                characters = "";
94
                for (int j = 32; j<=127; j++){
95
                        characters += (char) j;
96
                }
97
                characters += "?????????????????????????????????????????????????\n\r\f\t??";
98
        }
99
        
100
        /**
101
         * Return the content of a file that has been created 
102
         * from a URL using the HTTP GET protocol
103
         * @param url
104
         * The URL
105
         * @return
106
         * File containing this URL's content or null if no file was found.
107
         */
108
        private File getPreviousDownloadedURL(URL url){
109
                return getPreviousDownloaded(url);
110
        }
111

    
112
        /**
113
         * Return the content of a file that has been created 
114
         * from a URL using the HTTP POST protocol
115
         * @param url
116
         * The URL
117
         * @param data
118
         * The data to send on the query
119
         * @return
120
         * File containing this URL's content or null if no file was found.
121
         */
122
        private File getPreviousDownloadedURL(URL url, String data){
123
                return getPreviousDownloaded(url+data);
124
        }
125

    
126
        /**
127
         * Returns the content of a URL as a file from the file system.<br>
128
         * <p>
129
         * If the URL has been already downloaded in this session and notified
130
         * to the system using the static <b>Utilities.addDownloadedURL(URL)</b>
131
         * method, it can be restored faster from the file system avoiding to
132
         * download it again.
133
         * </p>
134
         * @param url
135
         * @return File containing this URL's content or null if no file was found.
136
         */
137
        private File getPreviousDownloaded(Object object){
138
                File f = null;
139
                if (downloadedFiles!=null && downloadedFiles.containsKey(object)){
140
                        String filePath = (String) downloadedFiles.get(object);
141
                        f = new File(filePath);
142
                        if (!f.exists())
143
                                return null;
144
                }
145
                return f;
146
        }
147

    
148
        /**
149
         * Adds an URL to the table of downloaded files for further uses. If the URL
150
         * already exists in the table its filePath value is updated to the new one and
151
         * the old file itself is removed from the file system.
152
         *
153
         * @param url
154
         * @param filePath
155
         */
156
        void addDownloadedURL(URL url, String filePath){
157
                if (downloadedFiles==null)
158
                        downloadedFiles = new Hashtable();
159
                String fileName = (String) downloadedFiles.put(url, filePath);
160
                //JMV: No se puede eliminar el anterior porque puede que alguien lo
161
                // este usando
162
                /*
163
        if (fileName!=null){
164
            File f = new File(fileName);
165
            if (f.exists())
166
                f.delete();
167
        }
168
                 */
169
        }
170

    
171
        /**
172
         * Downloads an URL into a temporary file that is removed the next time the
173
         * tempFileManager class is called, which means the next time gvSIG is launched.
174
         *
175
         * @param url
176
         * @param name
177
         * @return
178
         * @throws IOException
179
         * @throws ServerErrorResponseException
180
         * @throws ConnectException
181
         * @throws UnknownHostException
182
         */
183
        public synchronized File downloadFile(URL url, String name, ICancellable cancel) throws IOException,ConnectException, UnknownHostException{
184
                File f = null;
185

    
186
                if ((f=getPreviousDownloadedURL(url))==null){
187
                        File tempDirectory = new File(tempDirectoryPath);
188
                        if (!tempDirectory.exists())
189
                                tempDirectory.mkdir();
190

    
191
                        f = new File(calculateFileName(name));
192

    
193
                        if (cancel == null) {
194
                                cancel = new ICancellable() {
195
                                        public boolean isCanceled() {
196
                                                return false;
197
                                        }
198
                                        public Object getID(){
199
                                                return SEDownloader.class.getName();
200
                                        }
201
                                };
202
                        }
203
                        Thread downloader = new Thread(new Downloader(this, url, f, cancel.getID()));
204
                        Thread monitor = new Thread(new Monitor(this, cancel));
205
                        monitor.start();
206
                        downloader.start();
207
                        while(!getCanceled(cancel.getID()) && downloader.isAlive()) {
208
                                try {
209
                                        Thread.sleep(latency);
210
                                } catch (InterruptedException e) {
211
                                        // TODO Auto-generated catch block
212
                                        e.printStackTrace();
213
                                }
214
                        }
215

    
216
                        if (getCanceled(cancel.getID()))
217
                                return null;
218
                        downloader = null;
219
                        monitor = null;
220
                        if (this.downloadException!=null) {
221
                                Exception e = this.downloadException;
222
                                if (e instanceof FileNotFoundException)
223
                                        throw (IOException) e;
224
                                else if (e instanceof IOException)
225
                                        throw (IOException) e;
226
                                else if (e instanceof ConnectException)
227
                                        throw (ConnectException) e;
228
                                else if (e instanceof UnknownHostException)
229
                                        throw (UnknownHostException) e;
230
                        }
231
                } else {
232
                        System.out.println(url.toString()+" cached at '"+f.getAbsolutePath()+"'");
233
                }
234

    
235
                return f;
236
        }
237
        
238
        private String calculateFileName(String name){
239
                int index = name.lastIndexOf(".");
240
                if (index > 0){
241
                        return tempDirectoryPath + "/" + name.substring(0,index) + System.currentTimeMillis() + 
242
                                name.substring(index, name.length());
243
                }
244
                return tempDirectoryPath+"/"+name+System.currentTimeMillis();
245
        }
246

    
247
        /**
248
         * Downloads a URL using the HTTP Post protocol
249
         * @param url
250
         * The server URL
251
         * @param data
252
         * The data to send in the request
253
         * @param name
254
         * A common name for all the retrieved files
255
         * @param cancel
256
         * Used to cancel the downloads
257
         * @return
258
         * The retrieved file
259
         * @throws IOException
260
         * @throws ConnectException
261
         * @throws UnknownHostException
262
         */
263
        public synchronized File downloadFile(URL url, String data, String name, ICancellable cancel) throws IOException,ConnectException, UnknownHostException{
264
                File f = null;
265

    
266
                if ((f=getPreviousDownloadedURL(url,data))==null){
267
                        File tempDirectory = new File(tempDirectoryPath);
268
                        if (!tempDirectory.exists())
269
                                tempDirectory.mkdir();
270

    
271
                        f = new File(calculateFileName(name));
272

    
273
                        if (cancel == null) {
274
                                cancel = new ICancellable() {
275
                                        public boolean isCanceled() {
276
                                                return false;
277
                                        }
278
                                        public Object getID(){
279
                                                return SEDownloader.class.getName();
280
                                        }
281
                                };
282
                        }
283
                        Thread downloader = new Thread(new Downloader(this, url, data, f, cancel.getID()));
284
                        Thread monitor = new Thread(new Monitor(this, cancel));
285
                        monitor.start();
286
                        downloader.start();
287
                        while(!getCanceled(cancel.getID()) && downloader.isAlive()) {
288
                                try {
289
                                        Thread.sleep(latency);
290
                                } catch (InterruptedException e) {
291
                                        // TODO Auto-generated catch block
292
                                        e.printStackTrace();
293
                                }
294
                        }
295

    
296
                        if (getCanceled(cancel.getID()))
297
                                return null;
298
                        downloader = null;
299
                        monitor = null;
300
                        if (this.downloadException!=null) {
301
                                Exception e = this.downloadException;
302
                                if (e instanceof FileNotFoundException)
303
                                        throw (IOException) e;
304
                                else if (e instanceof IOException)
305
                                        throw (IOException) e;
306
                                else if (e instanceof ConnectException)
307
                                        throw (ConnectException) e;
308
                                else if (e instanceof UnknownHostException)
309
                                        throw (UnknownHostException) e;
310
                        }
311
                } else {
312
                        System.out.println(url.toString()+" cached at '"+f.getAbsolutePath()+"'");
313
                }
314

    
315
                return f;
316
        }
317

    
318
        /**
319
         * Try if a group of downloads has been canceled
320
         * @param groupId
321
         * Group id
322
         * @return
323
         * If the group has been canceled
324
         */
325
        protected boolean getCanceled(Object groupId){
326
                Object obj = canceledGroup.get(groupId);
327
                if (obj != null){
328
                        return ((Boolean)obj).booleanValue();
329
                }
330
                return false;
331
        }
332

    
333
        /**
334
         * Cancel a group of downloads
335
         * @param groupId
336
         * Group id
337
         * @param isCanceled
338
         * if the group has to be canceled
339
         */
340
        protected void setCanceled(Object groupId, boolean isCanceled){
341
                if (groupId == null){
342
                        groupId = SEDownloader.class.getName();
343
                }
344
                canceledGroup.put(groupId,new Boolean(isCanceled));
345
        }
346

    
347
        /**
348
         * Cleans every temporal file previously downloaded.
349
         */
350
        public void cleanUpTempFiles() {
351
                try{
352
                        File tempDirectory = new File(tempDirectoryPath);
353

    
354
                        File[] files = tempDirectory.listFiles();
355
                        if (files!=null) {
356
                                for (int i = 0; i < files.length; i++) {
357
                                        // s?lo por si en un futuro se necesitan crear directorios temporales
358
                                        if (files[i].isDirectory())        deleteDirectory(files[i]);
359
                                        files[i].delete();
360
                                }
361
                        }
362
                        tempDirectory.delete();
363
                } catch (Exception e) {        }
364

    
365
        }
366
        /**
367
         * Recursive directory delete.
368
         * @param f
369
         */
370
        private void deleteDirectory(File f) {
371
                File[] files = f.listFiles();
372
                for (int i = 0; i < files.length; i++) {
373
                        if (files[i].isDirectory()) deleteDirectory(files[i]);
374
                        files[i].delete();
375
                }
376

    
377
        }
378

    
379

    
380
        /**
381
         * Remove an URL from the system cache. The file will remain in the file
382
         * system for further eventual uses.
383
         * @param request
384
         */
385
        public void removeURL(URL url) {
386
                if (downloadedFiles != null && downloadedFiles.containsKey(url))
387
                        downloadedFiles.remove(url);
388
        }
389

    
390
        /**
391
         * Remove an URL from the system cache. The file will remain in the file
392
         * system for further eventual uses.
393
         * @param request
394
         */
395
        public void removeURL(Object url) {
396
                if (downloadedFiles != null && downloadedFiles.containsKey(url))
397
                        downloadedFiles.remove(url);
398
        }
399
}
400

    
401
final class Monitor implements Runnable {
402
        ICancellable c;
403
        SEDownloader downloader;
404
        
405
        public Monitor(SEDownloader downloader, ICancellable cancel) {
406
            downloader.setCanceled(cancel.getID(),false);
407
                this.c = cancel;
408
                this.downloader = downloader;
409
        }
410
        
411
        public void run() {
412
                while (!c.isCanceled()) {
413
                        try {
414
                                Thread.sleep(downloader.latency);
415
                        } catch (InterruptedException e) {
416
                                e.printStackTrace();
417
                        }
418
                }
419

    
420
                /*  WARNING!! This works because only one download is being processed at once.
421
                 *  You could prefer to start several transfers simultaneously. If so, you
422
                 *  should consideer using a non-static variable such is Utilities.canceled to
423
                 *  control when and which transfer in particular has been canceled.
424
                 *
425
                 *  The feature of transfer several files is at the moment under study. We are
426
                 *  planning to add an intelligent system that will give you a lot of services
427
                 *  and ease-of-use. So, we encourage you to wait for it instead of write your
428
                 *  own code.
429
                 */
430

    
431
                downloader.setCanceled(c.getID(),true);
432
        }
433
}
434

    
435
final class Downloader implements Runnable {
436
        private URL url;
437
        private File dstFile;
438
        private Object groupID = null;
439
        private String data = null;
440
        private SEDownloader downloader;
441
        
442
        public Downloader(SEDownloader downloader, URL url, File dstFile, Object groupID) {
443
                this.url = url;
444
                this.dstFile = dstFile;
445
                this.groupID = groupID;
446
                this.downloader = downloader;
447
                downloader.downloadException = null;
448
        }
449

    
450
        public Downloader(SEDownloader downloader, URL url, String data, File dstFile, Object groupID) {
451
                this.url = url;
452
                this.data = data;
453
                this.dstFile = dstFile;
454
                this.groupID = groupID;        
455
                this.downloader = downloader;
456
                downloader.downloadException = null;
457
        }
458

    
459
        public void run() {
460
                System.out.println("downloading '"+url.toString()+"' to: "+dstFile.getAbsolutePath());
461

    
462
                DataOutputStream dos;
463
                try {
464
                        DataInputStream is;
465
                        OutputStreamWriter os = null;
466
                        HttpURLConnection connection = null;
467
                        //If the used protocol is HTTPS
468
                        if (url.getProtocol().equals("https")){
469
                                disableHttsValidation();
470
                        }
471
                        connection = (HttpURLConnection)url.openConnection();
472
                        //If it uses a HTTP POST
473
                        if (data != null){
474
                                connection.setRequestProperty("SOAPAction","post");
475
                                connection.setRequestMethod("POST");
476
                                connection.setDoOutput(true);
477
                                connection.setRequestProperty("Content-Type", "text/xml; charset=UTF-8");
478
                                os = new OutputStreamWriter(connection.getOutputStream());
479
                                os.write(data);
480
                                os.flush();        
481
                                is = new DataInputStream(connection.getInputStream());
482
                        }else{
483
                                is = new DataInputStream(url.openStream());
484
                        }
485
                        
486
                        dos = new DataOutputStream( new BufferedOutputStream(new FileOutputStream(dstFile)));
487
                        byte[] buffer = new byte[1024*4];
488

    
489

    
490
                        long readed = 0;
491
                        for (int i = is.read(buffer); !downloader.getCanceled(groupID) && i>0; i = is.read(buffer)){
492
                                dos.write(buffer, 0, i);
493
                                readed += i;
494

    
495
                        }
496
                        if(os != null){
497
                                os.close();
498
                        }
499
                        dos.close();
500
                        is.close();
501
                        is = null;
502
                        dos = null;
503
                        if (downloader.getCanceled(groupID)) {
504
                                System.err.println("[RemoteServices] '"+url+"' CANCELED.");
505
                                dstFile.delete();
506
                                dstFile= null;
507
                        } else {
508
                            downloader.addDownloadedURL(url, dstFile.getAbsolutePath());
509
                        }
510
                } catch (Exception e) {
511
                        e.printStackTrace();
512
                        downloader.downloadException = e;
513
                }                
514
        }
515

    
516
        /**
517
         * This method disables the Https certificate validation.
518
         * @throws KeyManagementException
519
         * @throws NoSuchAlgorithmException
520
         */
521
        private void disableHttsValidation() throws KeyManagementException, NoSuchAlgorithmException{
522
                // Create a trust manager that does not validate certificate chains
523
                TrustManager[] trustAllCerts = new TrustManager[]{
524
                                new X509TrustManager() {
525
                                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
526
                                                return null;
527
                                        }
528
                                        public void checkClientTrusted(
529
                                                        java.security.cert.X509Certificate[] certs, String authType) {
530
                                        }
531
                                        public void checkServerTrusted(
532
                                                        java.security.cert.X509Certificate[] certs, String authType) {
533
                                        }
534
                                }
535
                };
536

    
537
                // Install the all-trusting trust manager
538
                SSLContext sc = SSLContext.getInstance("SSL");
539
                sc.init(null, trustAllCerts, new java.security.SecureRandom());
540
                HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
541
        }
542
}