Statistics
| Revision:

svn-gvsig-desktop / tags / v2_0_0_Build_2059 / libraries / libCompat / src / org / gvsig / compat / se / net / SEDownloader.java @ 39303

History | View | Annotate | Download (16.5 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
import java.util.prefs.Preferences;
59

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

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

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

    
70

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

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

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

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

    
179
        /**
180
         * Downloads an URL into a temporary file that is removed the next time the
181
         * tempFileManager class is called, which means the next time gvSIG is launched.
182
         *
183
         * @param url
184
         * @param name
185
         * @return
186
         * @throws IOException
187
         * @throws ServerErrorResponseException
188
         * @throws ConnectException
189
         * @throws UnknownHostException
190
         */
191
        public synchronized File downloadFile(URL url, String name, ICancellable cancel) throws IOException,ConnectException, UnknownHostException {
192
                File f = null;
193

    
194
                if ((f = getPreviousDownloadedURL(url)) == null) {
195
                        File tempDirectory = new File(tempDirectoryPath);
196
                        if (!tempDirectory.exists())
197
                                tempDirectory.mkdir();
198

    
199
                        f = new File(calculateFileName(name));
200

    
201
                        if (cancel == null) {
202
                                cancel = new ICancellable() {
203
                                        public boolean isCanceled() {
204
                                                return false;
205
                                        }
206
                                        public Object getID(){
207
                                                return SEDownloader.class.getName();
208
                                        }
209
                                };
210
                        }
211
                        
212
                        Monitor monitorObj = new Monitor(this, cancel);
213
                        Thread downloader = new Thread(new Downloader(this, url, f, cancel.getID()));
214
                        Thread monitor = new Thread(monitorObj);
215
                        
216
                        monitor.start();
217
                        downloader.start();
218
                        while(!getCanceled(cancel.getID()) && downloader.isAlive()) {
219
                                try {
220
                                        Thread.sleep(latency);
221
                                } catch (InterruptedException e) {
222
                                        LOG.error("Error", e);
223
                                }
224
                        }
225

    
226
                        try {
227
                                monitorObj.setFinish(true);
228
                                monitor.join();
229
                                downloader.join();
230
                        } catch (InterruptedException e1) {
231
                                LOG.warn(e1.getMessage());
232
                        }
233
                        downloader = null;
234
                        monitor = null;
235

    
236
                        if (getCanceled(cancel.getID()))
237
                                return null;
238
                        downloader = null;
239
                        monitor = null;
240
                        if (this.downloadException != null) {
241
                                Exception e = this.downloadException;
242
                                if (e instanceof FileNotFoundException)
243
                                        throw (IOException) e;
244
                                else if (e instanceof IOException)
245
                                        throw (IOException) e;
246
                                else if (e instanceof ConnectException)
247
                                        throw (ConnectException) e;
248
                                else if (e instanceof UnknownHostException)
249
                                        throw (UnknownHostException) e;
250
                        }
251
                } else {
252
                    LOG.info(url.toString() + " cached at '" + f.getAbsolutePath() + "'");
253
                }
254

    
255
                return f;
256
        }
257
        
258
        private String calculateFileName(String name) {
259
                count ++;
260
                int index = name.lastIndexOf(".");
261
                if (index > 0){
262
                        return tempDirectoryPath + "/" + name.substring(0,index) + System.currentTimeMillis() + count + 
263
                                name.substring(index, name.length());
264
                }
265
                return tempDirectoryPath + "/" + name + System.currentTimeMillis() + count;
266
        }
267

    
268

    
269
        /**
270
         * Downloads a URL using the HTTP Post protocol
271
         * @param url
272
         * The server URL
273
         * @param data
274
         * The data to send in the request
275
         * @param name
276
         * A common name for all the retrieved files
277
         * @param cancel
278
         * Used to cancel the downloads
279
         * @return
280
         * The retrieved file
281
         * @throws IOException
282
         * @throws ConnectException
283
         * @throws UnknownHostException
284
         */
285
        public synchronized File downloadFile(URL url, String data, String name, ICancellable cancel) throws IOException,ConnectException, UnknownHostException{
286
                File f = null;
287

    
288
                if ((f = getPreviousDownloadedURL(url,data)) == null) {
289
                        File tempDirectory = new File(tempDirectoryPath);
290
                        if (!tempDirectory.exists())
291
                                tempDirectory.mkdir();
292

    
293
                        f = new File(calculateFileName(name));
294

    
295
                        if (cancel == null) {
296
                                cancel = new ICancellable() {
297
                                        public boolean isCanceled() {
298
                                                return false;
299
                                        }
300
                                        public Object getID(){
301
                                                return SEDownloader.class.getName();
302
                                        }
303
                                };
304
                        }
305
                        Monitor monitorObj = new Monitor(this, cancel);
306
                        Thread downloader = new Thread(new Downloader(this, url, data, f, cancel.getID()));
307
                        Thread monitor = new Thread(monitorObj);
308
                        monitor.start();
309
                        downloader.start();
310
                        while(!getCanceled(cancel.getID()) && downloader.isAlive()) {
311
                                try {
312
                                        Thread.sleep(latency);
313
                                } catch (InterruptedException e) {
314
                                        LOG.error("Error", e);
315
                                }
316
                        }
317

    
318
                        try {
319
                                monitorObj.setFinish(true);
320
                                monitor.join();
321
                                downloader.join();
322
                        } catch (InterruptedException e1) {
323
                                LOG.warn(e1.getMessage());
324
                        }
325
                        downloader = null;
326
                        monitor = null;
327

    
328
                        if (getCanceled(cancel.getID()))
329
                                return null;
330
                        if (this.downloadException!=null) {
331
                                Exception e = this.downloadException;
332
                                if (e instanceof FileNotFoundException)
333
                                        throw (IOException) e;
334
                                else if (e instanceof IOException)
335
                                        throw (IOException) e;
336
                                else if (e instanceof ConnectException)
337
                                        throw (ConnectException) e;
338
                                else if (e instanceof UnknownHostException)
339
                                        throw (UnknownHostException) e;
340
                        }
341
                } else {
342
                        LOG.info(url.toString() + " cached at '" + f.getAbsolutePath() + "'");
343
                }
344

    
345
                return f;
346
        }
347

    
348
        /**
349
         * Try if a group of downloads has been canceled
350
         * @param groupId
351
         * Group id
352
         * @return
353
         * If the group has been canceled
354
         */
355
        protected boolean getCanceled(Object groupId) {
356
                Object obj = canceledGroup.get(groupId);
357
                if (obj != null) {
358
                        return ((Boolean)obj).booleanValue();
359
                }
360
                return false;
361
        }
362

    
363
        /**
364
         * Cancel a group of downloads
365
         * @param groupId
366
         * Group id
367
         * @param isCanceled
368
         * if the group has to be canceled
369
         */
370
        protected void setCanceled(Object groupId, boolean isCanceled) {
371
                if (groupId == null) {
372
                        groupId = SEDownloader.class.getName();
373
                }
374
                canceledGroup.put(groupId,new Boolean(isCanceled));
375
        }
376

    
377
        /**
378
         * Cleans every temporal file previously downloaded.
379
         */
380
        public void cleanUpTempFiles() {
381
                try{
382
                        File tempDirectory = new File(tempDirectoryPath);
383

    
384
                        File[] files = tempDirectory.listFiles();
385
                        if (files!=null) {
386
                                for (int i = 0; i < files.length; i++) {
387
                                        // s?lo por si en un futuro se necesitan crear directorios temporales
388
                                        if (files[i].isDirectory())        deleteDirectory(files[i]);
389
                                        files[i].delete();
390
                                }
391
                        }
392
                        tempDirectory.delete();
393
                } catch (Exception e) {        }
394

    
395
        }
396
        /**
397
         * Recursive directory delete.
398
         * @param f
399
         */
400
        private void deleteDirectory(File f) {
401
                File[] files = f.listFiles();
402
                for (int i = 0; i < files.length; i++) {
403
                        if (files[i].isDirectory()) 
404
                                deleteDirectory(files[i]);
405
                        files[i].delete();
406
                }
407

    
408
        }
409

    
410

    
411
        /**
412
         * Remove an URL from the system cache. The file will remain in the file
413
         * system for further eventual uses.
414
         * @param request
415
         */
416
        public void removeURL(URL url) {
417
                if (downloadedFiles != null && downloadedFiles.containsKey(url))
418
                        downloadedFiles.remove(url);
419
        }
420

    
421
        /**
422
         * Remove an URL from the system cache. The file will remain in the file
423
         * system for further eventual uses.
424
         * @param request
425
         */
426
        public void removeURL(Object url) {
427
                if (downloadedFiles != null && downloadedFiles.containsKey(url))
428
                        downloadedFiles.remove(url);
429
        }
430
}
431

    
432
final class Monitor implements Runnable {
433
        ICancellable c;
434
        private volatile boolean finish = false;
435
        SEDownloader downloader;
436
        private static Logger LOG = LoggerFactory.getLogger(Monitor.class);
437
        
438
        public Monitor(SEDownloader downloader, ICancellable cancel) {
439
            downloader.setCanceled(cancel.getID(),false);
440
                this.c = cancel;
441
                this.downloader = downloader;
442
        }
443
        
444
        public void run() {
445
                while (!c.isCanceled() && !getFinish()) {
446
                        try {
447
                                Thread.sleep(downloader.latency);
448
                        } catch (InterruptedException e) {
449
                                LOG.error("Error", e);
450
                        }
451
                }
452

    
453
                /*  WARNING!! This works because only one download is being processed at once.
454
                 *  You could prefer to start several transfers simultaneously. If so, you
455
                 *  should consideer using a non-static variable such is Utilities.canceled to
456
                 *  control when and which transfer in particular has been canceled.
457
                 *
458
                 *  The feature of transfer several files is at the moment under study. We are
459
                 *  planning to add an intelligent system that will give you a lot of services
460
                 *  and ease-of-use. So, we encourage you to wait for it instead of write your
461
                 *  own code.
462
                 */
463
                if(c.isCanceled())
464
                        downloader.setCanceled(c.getID(), true);
465
        }
466
        
467
        public synchronized void setFinish(boolean value) { 
468
                finish = value; 
469
        }
470
        
471
        public synchronized boolean getFinish() { 
472
                return finish; 
473
        }
474
}
475

    
476
final class Downloader implements Runnable {
477
        private URL url                    = null;
478
        private File dstFile               = null;
479
        private Object groupID             = null;
480
        private String data                = null;
481
        private SEDownloader downloader    = null;
482
        private static Logger LOG       = LoggerFactory.getLogger(Downloader.class);
483
        
484
        public Downloader(SEDownloader downloader, URL url, File dstFile, Object groupID) {
485
                this.url = url;
486
                this.dstFile = dstFile;
487
                this.groupID = groupID;
488
                this.downloader = downloader;
489
                downloader.downloadException = null;
490
        }
491

    
492
        public Downloader(SEDownloader downloader, URL url, String data, File dstFile, Object groupID) {
493
                this.url = url;
494
                this.data = data;
495
                this.dstFile = dstFile;
496
                this.groupID = groupID;        
497
                this.downloader = downloader;
498
                downloader.downloadException = null;
499
        }
500

    
501
        public void run() {
502
                LOG.info("downloading '" + url.toString() + "' to: " + dstFile.getAbsolutePath());
503
                if (data != null){
504
                    LOG.info("using POST, request = " + data);
505
                }
506
                // getting timeout from preferences in milliseconds.
507
                Preferences prefs = Preferences.userRoot().node( "gvsig.downloader" );
508
                // by default 1 minute (60000 milliseconds.
509
                int timeout = prefs.getInt("timeout", 60000);
510

    
511
                DataOutputStream dos;
512
                try {
513
                        DataInputStream is;
514
                        OutputStreamWriter os = null;
515
                        HttpURLConnection connection = null;
516
                        //If the used protocol is HTTPS
517
                        if (url.getProtocol().equals("https")) {
518
                                disableHttsValidation();
519
                        }
520
                        connection = (HttpURLConnection)url.openConnection();
521
                        connection.setConnectTimeout(timeout);
522
                        //If it uses a HTTP POST
523
                        if (data != null) {
524
                                connection.setRequestProperty("SOAPAction", "post");
525
                                connection.setRequestMethod("POST");
526
                                connection.setDoOutput(true);
527
                                connection.setRequestProperty("Content-Type", "text/xml; charset=UTF-8");
528
                                os = new OutputStreamWriter(connection.getOutputStream());
529
                                os.write(data);
530
                                os.flush();        
531
                                is = new DataInputStream(connection.getInputStream());
532
                        }else{
533
                                is = new DataInputStream(url.openStream());
534
                        }
535
                        
536
                        dos = new DataOutputStream( new BufferedOutputStream(new FileOutputStream(dstFile)));
537
                        byte[] buffer = new byte[1024 * 4];
538

    
539

    
540
                        long readed = 0;
541
                        for (int i = is.read(buffer); !downloader.getCanceled(groupID) && i>0; i = is.read(buffer)){
542
                                dos.write(buffer, 0, i);
543
                                readed += i;
544

    
545
                        }
546
                        if(os != null) {
547
                                os.close();
548
                        }
549
                        dos.close();
550
                        is.close();
551
                        is = null;
552
                        dos = null;
553
                        if (downloader.getCanceled(groupID)) {
554
                                LOG.info("[RemoteServices] '" + url + "' CANCELED.");
555
                                dstFile.delete();
556
                                dstFile = null;
557
                        } else {
558
                            downloader.addDownloadedURL(url, dstFile.getAbsolutePath());
559
                        }
560
                } catch (Exception e) {
561
                        LOG.info("Error downloading", e);
562
                        downloader.downloadException = e;
563
                }                
564
        }
565

    
566
        /**
567
         * This method disables the Https certificate validation.
568
         * @throws KeyManagementException
569
         * @throws NoSuchAlgorithmException
570
         */
571
        private void disableHttsValidation() throws KeyManagementException, NoSuchAlgorithmException{
572
                // Create a trust manager that does not validate certificate chains
573
                TrustManager[] trustAllCerts = new TrustManager[] {
574
                                new X509TrustManager() {
575
                                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
576
                                                return null;
577
                                        }
578
                                        public void checkClientTrusted(
579
                                                        java.security.cert.X509Certificate[] certs, String authType) {
580
                                        }
581
                                        public void checkServerTrusted(
582
                                                        java.security.cert.X509Certificate[] certs, String authType) {
583
                                        }
584
                                }
585
                };
586

    
587
                // Install the all-trusting trust manager
588
                SSLContext sc = SSLContext.getInstance("SSL");
589
                sc.init(null, trustAllCerts, new java.security.SecureRandom());
590
                HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
591
        }
592
}