Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.compat / org.gvsig.compat.se / src / main / java / org / gvsig / compat / se / net / SEDownloader.java @ 40559

History | View | Annotate | Download (18.3 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
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 3
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., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.compat.se.net;
25
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
26
 *
27
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
28
 *
29
 * This program is free software; you can redistribute it and/or
30
 * modify it under the terms of the GNU General Public License
31
 * as published by the Free Software Foundation; either version 2
32
 * of the License, or (at your option) any later version.
33
 *
34
 * This program is distributed in the hope that it will be useful,
35
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
37
 * GNU General Public License for more details.
38
 *
39
 * You should have received a copy of the GNU General Public License
40
 * along with this program; if not, write to the Free Software
41
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
42
 *
43
 * For more information, contact:
44
 *
45
 *  Generalitat Valenciana
46
 *   Conselleria d'Infraestructures i Transport
47
 *   Av. Blasco Ib??ez, 50
48
 *   46010 VALENCIA
49
 *   SPAIN
50
 *
51
 *      +34 963862235
52
 *   gvsig@gva.es
53
 *      www.gvsig.gva.es
54
 *
55
 *    or
56
 *
57
 *   IVER T.I. S.A
58
 *   Salamanca 50
59
 *   46005 Valencia
60
 *   Spain
61
 *
62
 *   +34 963163400
63
 *   dac@iver.es
64
 */
65

    
66
import java.io.BufferedOutputStream;
67
import java.io.DataInputStream;
68
import java.io.DataOutputStream;
69
import java.io.File;
70
import java.io.FileNotFoundException;
71
import java.io.FileOutputStream;
72
import java.io.IOException;
73
import java.io.OutputStreamWriter;
74
import java.net.ConnectException;
75
import java.net.HttpURLConnection;
76
import java.net.URI;
77
import java.net.URL;
78
import java.net.UnknownHostException;
79
import java.security.KeyManagementException;
80
import java.security.NoSuchAlgorithmException;
81
import java.util.Hashtable;
82
import java.util.prefs.Preferences;
83

    
84
import javax.net.ssl.HttpsURLConnection;
85
import javax.net.ssl.SSLContext;
86
import javax.net.ssl.TrustManager;
87
import javax.net.ssl.X509TrustManager;
88

    
89
import org.slf4j.Logger;
90
import org.slf4j.LoggerFactory;
91

    
92
import org.gvsig.compat.net.ICancellable;
93

    
94

    
95
/**
96
 * Clase con m?todos de utilidad en el protocolo WMS
97
 *
98
 * @authors Laura D?az, jaume dominguez faus
99
 */
100
public class SEDownloader implements org.gvsig.compat.net.Downloader{
101
    String                  characters;
102
        boolean                 canceled;
103
        final long              latency    = 500;
104
        private static int      count      = 0;
105
        private static Logger   LOG     = LoggerFactory.getLogger(SEDownloader.class);
106
        
107
        /**
108
         * Used to cancel a group of files
109
         * <b>key</b>: Group id, <b>value</b>: Boolean (true if
110
         * the group has to be canceled. Otherwise it is
111
         * false)
112
         */
113
        Hashtable canceledGroup = new Hashtable();
114
        /**
115
         * <b>key</b>: URL, <b>value</b>: path to the downloaded file.
116
         */
117
        Hashtable cachedURItoFile;
118
        Exception downloadException;
119
        final String tempDirectoryPath = System.getProperty("java.io.tmpdir")+"/tmp-andami";
120
    
121
        public SEDownloader() {
122
        super();  
123
                characters = "";
124
                for (int j = 32; j<=127; j++){
125
                        characters += (char) j;
126
                }
127
                characters += "?????????????????????????????????????????????????\n\r\f\t??";
128
        }
129
        
130
        /**
131
         * Return the content of a file that has been created 
132
         * from a URL using the HTTP GET protocol
133
         * @param url
134
         * The URL
135
         * @return
136
         * File containing this URL's content or null if no file was found.
137
         */
138
        private File getPreviousDownloadedURL(URL url){
139
                return getPreviousDownloaded(url);
140
        }
141

    
142
        /**
143
         * Return the content of a file that has been created 
144
         * from a URL using the HTTP POST protocol
145
         * @param url
146
         * The URL
147
         * @param data
148
         * The data to send on the query
149
         * @return
150
         * File containing this URL's content or null if no file was found.
151
         */
152
        private File getPreviousDownloadedURL(URL url, String data) {
153
                if(data == null)
154
                        return getPreviousDownloaded(url);
155
                return getPreviousDownloaded(url.toString() + data);
156
        }
157

    
158
        /**
159
         * Returns the content of a URL as a file from the file system.<br>
160
         * <p>
161
         * If the URL has been already downloaded in this session and notified
162
         * to the system using the static <b>Utilities.addDownloadedURL(URL)</b>
163
         * method, it can be restored faster from the file system avoiding to
164
         * download it again.
165
         * </p>
166
         * @param url
167
         * @return File containing this URL's content or null if no file was found.
168
         */
169
        private File getPreviousDownloaded(Object theurl) {
170
            
171
        File f = null;
172
            Object thekey = null;
173
        try {
174
            if (theurl instanceof URL) {
175
                thekey = ((URL) theurl).toURI();
176
            } else {
177
                thekey = theurl;
178
            }
179
        } catch (Exception e) {
180
            LOG.info("Warning: did not check url: " + theurl, e);
181
            return null;
182
        }
183
            
184
                if (cachedURItoFile != null && cachedURItoFile.containsKey(thekey)) {
185
                        String filePath = (String) cachedURItoFile.get(thekey);
186
                        f = new File(filePath);
187
                        if (!f.exists())
188
                                return null;
189
                }
190
                return f;
191
        }
192

    
193
        /**
194
         * Adds an URL to the table of downloaded files for further uses. If the URL
195
         * already exists in the table its filePath value is updated to the new one and
196
         * the old file itself is removed from the file system.
197
         *
198
         * @param url
199
         * @param filePath
200
         */
201
        void addDownloadedURL(URL url, String filePath) {
202
                if (cachedURItoFile == null)
203
                    cachedURItoFile = new Hashtable();
204
                
205
                URI theuri = null;
206
                try {
207
            theuri = url.toURI();
208
        } catch (Exception e) {
209
            LOG.info("Warning: did not cache bad url: " + url, e);
210
            return;
211
        }
212
                
213
                String fileName = (String) cachedURItoFile.put(theuri, filePath);
214
                //JMV: No se puede eliminar el anterior porque puede que alguien lo
215
                // este usando
216
                /*
217
        if (fileName!=null){
218
            File f = new File(fileName);
219
            if (f.exists())
220
                f.delete();
221
        }
222
                 */
223
        }
224

    
225
        /**
226
         * Downloads an URL into a temporary file that is removed the next time the
227
         * tempFileManager class is called, which means the next time gvSIG is launched.
228
         *
229
         * @param url
230
         * @param name
231
         * @return
232
         * @throws IOException
233
         * @throws ServerErrorResponseException
234
         * @throws ConnectException
235
         * @throws UnknownHostException
236
         */
237
        public synchronized File downloadFile(URL url, String name, ICancellable cancel) throws IOException,ConnectException, UnknownHostException {
238
                File f = null;
239

    
240
                if ((f = getPreviousDownloadedURL(url)) == null) {
241
                        File tempDirectory = new File(tempDirectoryPath);
242
                        if (!tempDirectory.exists())
243
                                tempDirectory.mkdir();
244

    
245
                        f = new File(calculateFileName(name));
246

    
247
                        if (cancel == null) {
248
                                cancel = new ICancellable() {
249
                                        public boolean isCanceled() {
250
                                                return false;
251
                                        }
252
                                        public Object getID(){
253
                                                return SEDownloader.class.getName();
254
                                        }
255
                                };
256
                        }
257
                        
258
                        Monitor monitorObj = new Monitor(this, cancel);
259
                        Thread downloader = new Thread(new Downloader(this, url, f, cancel.getID()));
260
                        Thread monitor = new Thread(monitorObj);
261
                        
262
                        monitor.start();
263
                        downloader.start();
264
                        while(!getCanceled(cancel.getID()) && downloader.isAlive()) {
265
                                try {
266
                                        Thread.sleep(latency);
267
                                } catch (InterruptedException e) {
268
                                        LOG.error("Error", e);
269
                                }
270
                        }
271

    
272
                        try {
273
                                monitorObj.setFinish(true);
274
                                monitor.join();
275
                                downloader.join();
276
                        } catch (InterruptedException e1) {
277
                                LOG.warn(e1.getMessage());
278
                        }
279
                        downloader = null;
280
                        monitor = null;
281

    
282
                        if (getCanceled(cancel.getID()))
283
                                return null;
284
                        downloader = null;
285
                        monitor = null;
286
                        if (this.downloadException != null) {
287
                                Exception e = this.downloadException;
288
                                if (e instanceof FileNotFoundException)
289
                                        throw (IOException) e;
290
                                else if (e instanceof IOException)
291
                                        throw (IOException) e;
292
                                else if (e instanceof ConnectException)
293
                                        throw (ConnectException) e;
294
                                else if (e instanceof UnknownHostException)
295
                                        throw (UnknownHostException) e;
296
                        }
297
                } else {
298
                    LOG.info(url.toString() + " cached at '" + f.getAbsolutePath() + "'");
299
                }
300

    
301
                return f;
302
        }
303
        
304
        private String calculateFileName(String name) {
305
                count ++;
306
                int index = name.lastIndexOf(".");
307
                if (index > 0){
308
                        return tempDirectoryPath + "/" + name.substring(0,index) + System.currentTimeMillis() + count + 
309
                                name.substring(index, name.length());
310
                }
311
                return tempDirectoryPath + "/" + name + System.currentTimeMillis() + count;
312
        }
313

    
314

    
315
        /**
316
         * Downloads a URL using the HTTP Post protocol
317
         * @param url
318
         * The server URL
319
         * @param data
320
         * The data to send in the request
321
         * @param name
322
         * A common name for all the retrieved files
323
         * @param cancel
324
         * Used to cancel the downloads
325
         * @return
326
         * The retrieved file
327
         * @throws IOException
328
         * @throws ConnectException
329
         * @throws UnknownHostException
330
         */
331
        public synchronized File downloadFile(URL url, String data, String name, ICancellable cancel) throws IOException,ConnectException, UnknownHostException{
332
                File f = null;
333

    
334
                if ((f = getPreviousDownloadedURL(url,data)) == null) {
335
                        File tempDirectory = new File(tempDirectoryPath);
336
                        if (!tempDirectory.exists())
337
                                tempDirectory.mkdir();
338

    
339
                        f = new File(calculateFileName(name));
340

    
341
                        if (cancel == null) {
342
                                cancel = new ICancellable() {
343
                                        public boolean isCanceled() {
344
                                                return false;
345
                                        }
346
                                        public Object getID(){
347
                                                return SEDownloader.class.getName();
348
                                        }
349
                                };
350
                        }
351
                        Monitor monitorObj = new Monitor(this, cancel);
352
                        Thread downloader = new Thread(new Downloader(this, url, data, f, cancel.getID()));
353
                        Thread monitor = new Thread(monitorObj);
354
                        monitor.start();
355
                        downloader.start();
356
                        while(!getCanceled(cancel.getID()) && downloader.isAlive()) {
357
                                try {
358
                                        Thread.sleep(latency);
359
                                } catch (InterruptedException e) {
360
                                        LOG.error("Error", e);
361
                                }
362
                        }
363

    
364
                        try {
365
                                monitorObj.setFinish(true);
366
                                monitor.join();
367
                                downloader.join();
368
                        } catch (InterruptedException e1) {
369
                                LOG.warn(e1.getMessage());
370
                        }
371
                        downloader = null;
372
                        monitor = null;
373

    
374
                        if (getCanceled(cancel.getID()))
375
                                return null;
376
                        if (this.downloadException!=null) {
377
                                Exception e = this.downloadException;
378
                                if (e instanceof FileNotFoundException)
379
                                        throw (IOException) e;
380
                                else if (e instanceof IOException)
381
                                        throw (IOException) e;
382
                                else if (e instanceof ConnectException)
383
                                        throw (ConnectException) e;
384
                                else if (e instanceof UnknownHostException)
385
                                        throw (UnknownHostException) e;
386
                        }
387
                } else {
388
                        LOG.info(url.toString() + " cached at '" + f.getAbsolutePath() + "'");
389
                }
390

    
391
                return f;
392
        }
393

    
394
        /**
395
         * Try if a group of downloads has been canceled
396
         * @param groupId
397
         * Group id
398
         * @return
399
         * If the group has been canceled
400
         */
401
        protected boolean getCanceled(Object groupId) {
402
                Object obj = canceledGroup.get(groupId);
403
                if (obj != null) {
404
                        return ((Boolean)obj).booleanValue();
405
                }
406
                return false;
407
        }
408

    
409
        /**
410
         * Cancel a group of downloads
411
         * @param groupId
412
         * Group id
413
         * @param isCanceled
414
         * if the group has to be canceled
415
         */
416
        protected void setCanceled(Object groupId, boolean isCanceled) {
417
                if (groupId == null) {
418
                        groupId = SEDownloader.class.getName();
419
                }
420
                canceledGroup.put(groupId,new Boolean(isCanceled));
421
        }
422

    
423
        /**
424
         * Cleans every temporal file previously downloaded.
425
         */
426
        public void cleanUpTempFiles() {
427
                try{
428
                        File tempDirectory = new File(tempDirectoryPath);
429

    
430
                        File[] files = tempDirectory.listFiles();
431
                        if (files!=null) {
432
                                for (int i = 0; i < files.length; i++) {
433
                                        // s?lo por si en un futuro se necesitan crear directorios temporales
434
                                        if (files[i].isDirectory())        deleteDirectory(files[i]);
435
                                        files[i].delete();
436
                                }
437
                        }
438
                        tempDirectory.delete();
439
                } catch (Exception e) {        }
440

    
441
        }
442
        /**
443
         * Recursive directory delete.
444
         * @param f
445
         */
446
        private void deleteDirectory(File f) {
447
                File[] files = f.listFiles();
448
                for (int i = 0; i < files.length; i++) {
449
                        if (files[i].isDirectory()) 
450
                                deleteDirectory(files[i]);
451
                        files[i].delete();
452
                }
453

    
454
        }
455

    
456

    
457
        /**
458
         * Remove an URL from the system cache. The file will remain in the file
459
         * system for further eventual uses.
460
         * @param request
461
         */
462
        public void removeURL(URL url) {
463
            
464
            URI theuri = null;
465

    
466
        try {
467
            theuri = url.toURI();
468
        } catch (Exception e) {
469
            LOG.info("Warning: did not remove bad url: " + url, e);
470
            return;
471
        }
472
            
473
            
474
                if (cachedURItoFile != null && cachedURItoFile.containsKey(theuri))
475
                    cachedURItoFile.remove(theuri);
476
        }
477

    
478
        /**
479
         * Remove an URL from the system cache. The file will remain in the file
480
         * system for further eventual uses.
481
         * @param request
482
         */
483
        public void removeURL(Object url) {
484
                if (cachedURItoFile != null && cachedURItoFile.containsKey(url))
485
                    cachedURItoFile.remove(url);
486
        }
487
}
488

    
489
final class Monitor implements Runnable {
490
        ICancellable c;
491
        private volatile boolean finish = false;
492
        SEDownloader downloader;
493
        private static Logger LOG = LoggerFactory.getLogger(Monitor.class);
494
        
495
        public Monitor(SEDownloader downloader, ICancellable cancel) {
496
            downloader.setCanceled(cancel.getID(),false);
497
                this.c = cancel;
498
                this.downloader = downloader;
499
        }
500
        
501
        public void run() {
502
                while (!c.isCanceled() && !getFinish()) {
503
                        try {
504
                                Thread.sleep(downloader.latency);
505
                        } catch (InterruptedException e) {
506
                                LOG.error("Error", e);
507
                        }
508
                }
509

    
510
                /*  WARNING!! This works because only one download is being processed at once.
511
                 *  You could prefer to start several transfers simultaneously. If so, you
512
                 *  should consideer using a non-static variable such is Utilities.canceled to
513
                 *  control when and which transfer in particular has been canceled.
514
                 *
515
                 *  The feature of transfer several files is at the moment under study. We are
516
                 *  planning to add an intelligent system that will give you a lot of services
517
                 *  and ease-of-use. So, we encourage you to wait for it instead of write your
518
                 *  own code.
519
                 */
520
                if(c.isCanceled())
521
                        downloader.setCanceled(c.getID(), true);
522
        }
523
        
524
        public synchronized void setFinish(boolean value) { 
525
                finish = value; 
526
        }
527
        
528
        public synchronized boolean getFinish() { 
529
                return finish; 
530
        }
531
}
532

    
533
final class Downloader implements Runnable {
534
        private URL url                    = null;
535
        private File dstFile               = null;
536
        private Object groupID             = null;
537
        private String data                = null;
538
        private SEDownloader downloader    = null;
539
        private static Logger LOG       = LoggerFactory.getLogger(Downloader.class);
540
        
541
        public Downloader(SEDownloader downloader, URL url, File dstFile, Object groupID) {
542
                this.url = url;
543
                this.dstFile = dstFile;
544
                this.groupID = groupID;
545
                this.downloader = downloader;
546
                downloader.downloadException = null;
547
        }
548

    
549
        public Downloader(SEDownloader downloader, URL url, String data, File dstFile, Object groupID) {
550
                this.url = url;
551
                this.data = data;
552
                this.dstFile = dstFile;
553
                this.groupID = groupID;        
554
                this.downloader = downloader;
555
                downloader.downloadException = null;
556
        }
557

    
558
        public void run() {
559
                LOG.info("downloading '" + url.toString() + "' to: " + dstFile.getAbsolutePath());
560
                if (data != null){
561
                    LOG.info("using POST, request = " + data);
562
                }
563
                // getting timeout from preferences in milliseconds.
564
                Preferences prefs = Preferences.userRoot().node( "gvsig.downloader" );
565
                // by default 1 minute (60000 milliseconds.
566
                int timeout = prefs.getInt("timeout", 60000);
567

    
568
                DataOutputStream dos;
569
                try {
570
                        DataInputStream is;
571
                        OutputStreamWriter os = null;
572
                        HttpURLConnection connection = null;
573
                        //If the used protocol is HTTPS
574
                        if (url.getProtocol().equals("https")) {
575
                                disableHttsValidation();
576
                        }
577
                        connection = (HttpURLConnection)url.openConnection();
578
                        connection.setUseCaches(false);
579
                        connection.setConnectTimeout(timeout);
580
                        //If it uses a HTTP POST
581
                        if (data != null) {
582
                                connection.setRequestProperty("SOAPAction", "post");
583
                                connection.setRequestMethod("POST");
584
                                connection.setDoOutput(true);
585
                                connection.setRequestProperty("Content-Type", "text/xml; charset=UTF-8");
586
                                os = new OutputStreamWriter(connection.getOutputStream());
587
                                os.write(data);
588
                                os.flush();        
589
                                is = new DataInputStream(connection.getInputStream());
590
                        }else{
591
                                is = new DataInputStream(url.openStream());
592
                        }
593
                        
594
                        dos = new DataOutputStream( new BufferedOutputStream(new FileOutputStream(dstFile)));
595
                        byte[] buffer = new byte[1024 * 4];
596

    
597

    
598
                        long readed = 0;
599
                        for (int i = is.read(buffer); !downloader.getCanceled(groupID) && i>0; i = is.read(buffer)){
600
                                dos.write(buffer, 0, i);
601
                                readed += i;
602

    
603
                        }
604
                        if(os != null) {
605
                                os.close();
606
                        }
607
                        dos.close();
608
                        is.close();
609
                        is = null;
610
                        dos = null;
611
                        if (downloader.getCanceled(groupID)) {
612
                                LOG.info("[RemoteServices] '" + url + "' CANCELED.");
613
                                dstFile.delete();
614
                                dstFile = null;
615
                        } else {
616
                            downloader.addDownloadedURL(url, dstFile.getAbsolutePath());
617
                        }
618
                } catch (Exception e) {
619
                        LOG.info("Error downloading", e);
620
                        downloader.downloadException = e;
621
                }                
622
        }
623

    
624
        /**
625
         * This method disables the Https certificate validation.
626
         * @throws KeyManagementException
627
         * @throws NoSuchAlgorithmException
628
         */
629
        private void disableHttsValidation() throws KeyManagementException, NoSuchAlgorithmException{
630
                // Create a trust manager that does not validate certificate chains
631
                TrustManager[] trustAllCerts = new TrustManager[] {
632
                                new X509TrustManager() {
633
                                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
634
                                                return null;
635
                                        }
636
                                        public void checkClientTrusted(
637
                                                        java.security.cert.X509Certificate[] certs, String authType) {
638
                                        }
639
                                        public void checkServerTrusted(
640
                                                        java.security.cert.X509Certificate[] certs, String authType) {
641
                                        }
642
                                }
643
                };
644

    
645
                // Install the all-trusting trust manager
646
                SSLContext sc = SSLContext.getInstance("SSL");
647
                sc.init(null, trustAllCerts, new java.security.SecureRandom());
648
                HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
649
        }
650
}