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 @ 40435

History | View | Annotate | Download (17.4 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.URI;
54
import java.net.URL;
55
import java.net.UnknownHostException;
56
import java.security.KeyManagementException;
57
import java.security.NoSuchAlgorithmException;
58
import java.util.Hashtable;
59
import java.util.prefs.Preferences;
60

    
61
import javax.net.ssl.HttpsURLConnection;
62
import javax.net.ssl.SSLContext;
63
import javax.net.ssl.TrustManager;
64
import javax.net.ssl.X509TrustManager;
65

    
66
import org.slf4j.Logger;
67
import org.slf4j.LoggerFactory;
68

    
69
import org.gvsig.compat.net.ICancellable;
70

    
71

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

    
119
        /**
120
         * Return the content of a file that has been created 
121
         * from a URL using the HTTP POST protocol
122
         * @param url
123
         * The URL
124
         * @param data
125
         * The data to send on the query
126
         * @return
127
         * File containing this URL's content or null if no file was found.
128
         */
129
        private File getPreviousDownloadedURL(URL url, String data) {
130
                if(data == null)
131
                        return getPreviousDownloaded(url);
132
                return getPreviousDownloaded(url.toString() + data);
133
        }
134

    
135
        /**
136
         * Returns the content of a URL as a file from the file system.<br>
137
         * <p>
138
         * If the URL has been already downloaded in this session and notified
139
         * to the system using the static <b>Utilities.addDownloadedURL(URL)</b>
140
         * method, it can be restored faster from the file system avoiding to
141
         * download it again.
142
         * </p>
143
         * @param url
144
         * @return File containing this URL's content or null if no file was found.
145
         */
146
        private File getPreviousDownloaded(Object theurl) {
147
            
148
        File f = null;
149
            Object thekey = null;
150
        try {
151
            if (theurl instanceof URL) {
152
                thekey = ((URL) theurl).toURI();
153
            } else {
154
                thekey = theurl;
155
            }
156
        } catch (Exception e) {
157
            LOG.info("Warning: did not check url: " + theurl, e);
158
            return null;
159
        }
160
            
161
                if (cachedURItoFile != null && cachedURItoFile.containsKey(thekey)) {
162
                        String filePath = (String) cachedURItoFile.get(thekey);
163
                        f = new File(filePath);
164
                        if (!f.exists())
165
                                return null;
166
                }
167
                return f;
168
        }
169

    
170
        /**
171
         * Adds an URL to the table of downloaded files for further uses. If the URL
172
         * already exists in the table its filePath value is updated to the new one and
173
         * the old file itself is removed from the file system.
174
         *
175
         * @param url
176
         * @param filePath
177
         */
178
        void addDownloadedURL(URL url, String filePath) {
179
                if (cachedURItoFile == null)
180
                    cachedURItoFile = new Hashtable();
181
                
182
                URI theuri = null;
183
                try {
184
            theuri = url.toURI();
185
        } catch (Exception e) {
186
            LOG.info("Warning: did not cache bad url: " + url, e);
187
            return;
188
        }
189
                
190
                String fileName = (String) cachedURItoFile.put(theuri, filePath);
191
                //JMV: No se puede eliminar el anterior porque puede que alguien lo
192
                // este usando
193
                /*
194
        if (fileName!=null){
195
            File f = new File(fileName);
196
            if (f.exists())
197
                f.delete();
198
        }
199
                 */
200
        }
201

    
202
        /**
203
         * Downloads an URL into a temporary file that is removed the next time the
204
         * tempFileManager class is called, which means the next time gvSIG is launched.
205
         *
206
         * @param url
207
         * @param name
208
         * @return
209
         * @throws IOException
210
         * @throws ServerErrorResponseException
211
         * @throws ConnectException
212
         * @throws UnknownHostException
213
         */
214
        public synchronized File downloadFile(URL url, String name, ICancellable cancel) throws IOException,ConnectException, UnknownHostException {
215
                File f = null;
216

    
217
                if ((f = getPreviousDownloadedURL(url)) == null) {
218
                        File tempDirectory = new File(tempDirectoryPath);
219
                        if (!tempDirectory.exists())
220
                                tempDirectory.mkdir();
221

    
222
                        f = new File(calculateFileName(name));
223

    
224
                        if (cancel == null) {
225
                                cancel = new ICancellable() {
226
                                        public boolean isCanceled() {
227
                                                return false;
228
                                        }
229
                                        public Object getID(){
230
                                                return SEDownloader.class.getName();
231
                                        }
232
                                };
233
                        }
234
                        
235
                        Monitor monitorObj = new Monitor(this, cancel);
236
                        Thread downloader = new Thread(new Downloader(this, url, f, cancel.getID()));
237
                        Thread monitor = new Thread(monitorObj);
238
                        
239
                        monitor.start();
240
                        downloader.start();
241
                        while(!getCanceled(cancel.getID()) && downloader.isAlive()) {
242
                                try {
243
                                        Thread.sleep(latency);
244
                                } catch (InterruptedException e) {
245
                                        LOG.error("Error", e);
246
                                }
247
                        }
248

    
249
                        try {
250
                                monitorObj.setFinish(true);
251
                                monitor.join();
252
                                downloader.join();
253
                        } catch (InterruptedException e1) {
254
                                LOG.warn(e1.getMessage());
255
                        }
256
                        downloader = null;
257
                        monitor = null;
258

    
259
                        if (getCanceled(cancel.getID()))
260
                                return null;
261
                        downloader = null;
262
                        monitor = null;
263
                        if (this.downloadException != null) {
264
                                Exception e = this.downloadException;
265
                                if (e instanceof FileNotFoundException)
266
                                        throw (IOException) e;
267
                                else if (e instanceof IOException)
268
                                        throw (IOException) e;
269
                                else if (e instanceof ConnectException)
270
                                        throw (ConnectException) e;
271
                                else if (e instanceof UnknownHostException)
272
                                        throw (UnknownHostException) e;
273
                        }
274
                } else {
275
                    LOG.info(url.toString() + " cached at '" + f.getAbsolutePath() + "'");
276
                }
277

    
278
                return f;
279
        }
280
        
281
        private String calculateFileName(String name) {
282
                count ++;
283
                int index = name.lastIndexOf(".");
284
                if (index > 0){
285
                        return tempDirectoryPath + "/" + name.substring(0,index) + System.currentTimeMillis() + count + 
286
                                name.substring(index, name.length());
287
                }
288
                return tempDirectoryPath + "/" + name + System.currentTimeMillis() + count;
289
        }
290

    
291

    
292
        /**
293
         * Downloads a URL using the HTTP Post protocol
294
         * @param url
295
         * The server URL
296
         * @param data
297
         * The data to send in the request
298
         * @param name
299
         * A common name for all the retrieved files
300
         * @param cancel
301
         * Used to cancel the downloads
302
         * @return
303
         * The retrieved file
304
         * @throws IOException
305
         * @throws ConnectException
306
         * @throws UnknownHostException
307
         */
308
        public synchronized File downloadFile(URL url, String data, String name, ICancellable cancel) throws IOException,ConnectException, UnknownHostException{
309
                File f = null;
310

    
311
                if ((f = getPreviousDownloadedURL(url,data)) == null) {
312
                        File tempDirectory = new File(tempDirectoryPath);
313
                        if (!tempDirectory.exists())
314
                                tempDirectory.mkdir();
315

    
316
                        f = new File(calculateFileName(name));
317

    
318
                        if (cancel == null) {
319
                                cancel = new ICancellable() {
320
                                        public boolean isCanceled() {
321
                                                return false;
322
                                        }
323
                                        public Object getID(){
324
                                                return SEDownloader.class.getName();
325
                                        }
326
                                };
327
                        }
328
                        Monitor monitorObj = new Monitor(this, cancel);
329
                        Thread downloader = new Thread(new Downloader(this, url, data, f, cancel.getID()));
330
                        Thread monitor = new Thread(monitorObj);
331
                        monitor.start();
332
                        downloader.start();
333
                        while(!getCanceled(cancel.getID()) && downloader.isAlive()) {
334
                                try {
335
                                        Thread.sleep(latency);
336
                                } catch (InterruptedException e) {
337
                                        LOG.error("Error", e);
338
                                }
339
                        }
340

    
341
                        try {
342
                                monitorObj.setFinish(true);
343
                                monitor.join();
344
                                downloader.join();
345
                        } catch (InterruptedException e1) {
346
                                LOG.warn(e1.getMessage());
347
                        }
348
                        downloader = null;
349
                        monitor = null;
350

    
351
                        if (getCanceled(cancel.getID()))
352
                                return null;
353
                        if (this.downloadException!=null) {
354
                                Exception e = this.downloadException;
355
                                if (e instanceof FileNotFoundException)
356
                                        throw (IOException) e;
357
                                else if (e instanceof IOException)
358
                                        throw (IOException) e;
359
                                else if (e instanceof ConnectException)
360
                                        throw (ConnectException) e;
361
                                else if (e instanceof UnknownHostException)
362
                                        throw (UnknownHostException) e;
363
                        }
364
                } else {
365
                        LOG.info(url.toString() + " cached at '" + f.getAbsolutePath() + "'");
366
                }
367

    
368
                return f;
369
        }
370

    
371
        /**
372
         * Try if a group of downloads has been canceled
373
         * @param groupId
374
         * Group id
375
         * @return
376
         * If the group has been canceled
377
         */
378
        protected boolean getCanceled(Object groupId) {
379
                Object obj = canceledGroup.get(groupId);
380
                if (obj != null) {
381
                        return ((Boolean)obj).booleanValue();
382
                }
383
                return false;
384
        }
385

    
386
        /**
387
         * Cancel a group of downloads
388
         * @param groupId
389
         * Group id
390
         * @param isCanceled
391
         * if the group has to be canceled
392
         */
393
        protected void setCanceled(Object groupId, boolean isCanceled) {
394
                if (groupId == null) {
395
                        groupId = SEDownloader.class.getName();
396
                }
397
                canceledGroup.put(groupId,new Boolean(isCanceled));
398
        }
399

    
400
        /**
401
         * Cleans every temporal file previously downloaded.
402
         */
403
        public void cleanUpTempFiles() {
404
                try{
405
                        File tempDirectory = new File(tempDirectoryPath);
406

    
407
                        File[] files = tempDirectory.listFiles();
408
                        if (files!=null) {
409
                                for (int i = 0; i < files.length; i++) {
410
                                        // s?lo por si en un futuro se necesitan crear directorios temporales
411
                                        if (files[i].isDirectory())        deleteDirectory(files[i]);
412
                                        files[i].delete();
413
                                }
414
                        }
415
                        tempDirectory.delete();
416
                } catch (Exception e) {        }
417

    
418
        }
419
        /**
420
         * Recursive directory delete.
421
         * @param f
422
         */
423
        private void deleteDirectory(File f) {
424
                File[] files = f.listFiles();
425
                for (int i = 0; i < files.length; i++) {
426
                        if (files[i].isDirectory()) 
427
                                deleteDirectory(files[i]);
428
                        files[i].delete();
429
                }
430

    
431
        }
432

    
433

    
434
        /**
435
         * Remove an URL from the system cache. The file will remain in the file
436
         * system for further eventual uses.
437
         * @param request
438
         */
439
        public void removeURL(URL url) {
440
            
441
            URI theuri = null;
442

    
443
        try {
444
            theuri = url.toURI();
445
        } catch (Exception e) {
446
            LOG.info("Warning: did not remove bad url: " + url, e);
447
            return;
448
        }
449
            
450
            
451
                if (cachedURItoFile != null && cachedURItoFile.containsKey(theuri))
452
                    cachedURItoFile.remove(theuri);
453
        }
454

    
455
        /**
456
         * Remove an URL from the system cache. The file will remain in the file
457
         * system for further eventual uses.
458
         * @param request
459
         */
460
        public void removeURL(Object url) {
461
                if (cachedURItoFile != null && cachedURItoFile.containsKey(url))
462
                    cachedURItoFile.remove(url);
463
        }
464
}
465

    
466
final class Monitor implements Runnable {
467
        ICancellable c;
468
        private volatile boolean finish = false;
469
        SEDownloader downloader;
470
        private static Logger LOG = LoggerFactory.getLogger(Monitor.class);
471
        
472
        public Monitor(SEDownloader downloader, ICancellable cancel) {
473
            downloader.setCanceled(cancel.getID(),false);
474
                this.c = cancel;
475
                this.downloader = downloader;
476
        }
477
        
478
        public void run() {
479
                while (!c.isCanceled() && !getFinish()) {
480
                        try {
481
                                Thread.sleep(downloader.latency);
482
                        } catch (InterruptedException e) {
483
                                LOG.error("Error", e);
484
                        }
485
                }
486

    
487
                /*  WARNING!! This works because only one download is being processed at once.
488
                 *  You could prefer to start several transfers simultaneously. If so, you
489
                 *  should consideer using a non-static variable such is Utilities.canceled to
490
                 *  control when and which transfer in particular has been canceled.
491
                 *
492
                 *  The feature of transfer several files is at the moment under study. We are
493
                 *  planning to add an intelligent system that will give you a lot of services
494
                 *  and ease-of-use. So, we encourage you to wait for it instead of write your
495
                 *  own code.
496
                 */
497
                if(c.isCanceled())
498
                        downloader.setCanceled(c.getID(), true);
499
        }
500
        
501
        public synchronized void setFinish(boolean value) { 
502
                finish = value; 
503
        }
504
        
505
        public synchronized boolean getFinish() { 
506
                return finish; 
507
        }
508
}
509

    
510
final class Downloader implements Runnable {
511
        private URL url                    = null;
512
        private File dstFile               = null;
513
        private Object groupID             = null;
514
        private String data                = null;
515
        private SEDownloader downloader    = null;
516
        private static Logger LOG       = LoggerFactory.getLogger(Downloader.class);
517
        
518
        public Downloader(SEDownloader downloader, URL url, File dstFile, Object groupID) {
519
                this.url = url;
520
                this.dstFile = dstFile;
521
                this.groupID = groupID;
522
                this.downloader = downloader;
523
                downloader.downloadException = null;
524
        }
525

    
526
        public Downloader(SEDownloader downloader, URL url, String data, File dstFile, Object groupID) {
527
                this.url = url;
528
                this.data = data;
529
                this.dstFile = dstFile;
530
                this.groupID = groupID;        
531
                this.downloader = downloader;
532
                downloader.downloadException = null;
533
        }
534

    
535
        public void run() {
536
                LOG.info("downloading '" + url.toString() + "' to: " + dstFile.getAbsolutePath());
537
                if (data != null){
538
                    LOG.info("using POST, request = " + data);
539
                }
540
                // getting timeout from preferences in milliseconds.
541
                Preferences prefs = Preferences.userRoot().node( "gvsig.downloader" );
542
                // by default 1 minute (60000 milliseconds.
543
                int timeout = prefs.getInt("timeout", 60000);
544

    
545
                DataOutputStream dos;
546
                try {
547
                        DataInputStream is;
548
                        OutputStreamWriter os = null;
549
                        HttpURLConnection connection = null;
550
                        //If the used protocol is HTTPS
551
                        if (url.getProtocol().equals("https")) {
552
                                disableHttsValidation();
553
                        }
554
                        connection = (HttpURLConnection)url.openConnection();
555
                        connection.setUseCaches(false);
556
                        connection.setConnectTimeout(timeout);
557
                        //If it uses a HTTP POST
558
                        if (data != null) {
559
                                connection.setRequestProperty("SOAPAction", "post");
560
                                connection.setRequestMethod("POST");
561
                                connection.setDoOutput(true);
562
                                connection.setRequestProperty("Content-Type", "text/xml; charset=UTF-8");
563
                                os = new OutputStreamWriter(connection.getOutputStream());
564
                                os.write(data);
565
                                os.flush();        
566
                                is = new DataInputStream(connection.getInputStream());
567
                        }else{
568
                                is = new DataInputStream(url.openStream());
569
                        }
570
                        
571
                        dos = new DataOutputStream( new BufferedOutputStream(new FileOutputStream(dstFile)));
572
                        byte[] buffer = new byte[1024 * 4];
573

    
574

    
575
                        long readed = 0;
576
                        for (int i = is.read(buffer); !downloader.getCanceled(groupID) && i>0; i = is.read(buffer)){
577
                                dos.write(buffer, 0, i);
578
                                readed += i;
579

    
580
                        }
581
                        if(os != null) {
582
                                os.close();
583
                        }
584
                        dos.close();
585
                        is.close();
586
                        is = null;
587
                        dos = null;
588
                        if (downloader.getCanceled(groupID)) {
589
                                LOG.info("[RemoteServices] '" + url + "' CANCELED.");
590
                                dstFile.delete();
591
                                dstFile = null;
592
                        } else {
593
                            downloader.addDownloadedURL(url, dstFile.getAbsolutePath());
594
                        }
595
                } catch (Exception e) {
596
                        LOG.info("Error downloading", e);
597
                        downloader.downloadException = e;
598
                }                
599
        }
600

    
601
        /**
602
         * This method disables the Https certificate validation.
603
         * @throws KeyManagementException
604
         * @throws NoSuchAlgorithmException
605
         */
606
        private void disableHttsValidation() throws KeyManagementException, NoSuchAlgorithmException{
607
                // Create a trust manager that does not validate certificate chains
608
                TrustManager[] trustAllCerts = new TrustManager[] {
609
                                new X509TrustManager() {
610
                                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
611
                                                return null;
612
                                        }
613
                                        public void checkClientTrusted(
614
                                                        java.security.cert.X509Certificate[] certs, String authType) {
615
                                        }
616
                                        public void checkServerTrusted(
617
                                                        java.security.cert.X509Certificate[] certs, String authType) {
618
                                        }
619
                                }
620
                };
621

    
622
                // Install the all-trusting trust manager
623
                SSLContext sc = SSLContext.getInstance("SSL");
624
                sc.init(null, trustAllCerts, new java.security.SecureRandom());
625
                HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
626
        }
627
}