JAL-3130 adapted getdown src. attempt 2. first attempt failed due to cp'ed .git files
[jalview.git] / getdown / src / getdown / core / src / main / java / com / threerings / getdown / net / HTTPDownloader.java
1 //
2 // Getdown - application installer, patcher and launcher
3 // Copyright (C) 2004-2018 Getdown authors
4 // https://github.com/threerings/getdown/blob/master/LICENSE
5
6 package com.threerings.getdown.net;
7
8 import java.io.File;
9 import java.io.FileOutputStream;
10 import java.io.IOException;
11 import java.io.InputStream;
12 import java.net.HttpURLConnection;
13 import java.net.Proxy;
14 import java.net.URL;
15 import java.net.URLConnection;
16 import java.nio.channels.Channels;
17 import java.nio.channels.ReadableByteChannel;
18
19 import com.threerings.getdown.data.Resource;
20 import com.threerings.getdown.util.ConnectionUtil;
21
22 import static com.threerings.getdown.Log.log;
23
24 /**
25  * Implements downloading files over HTTP
26  */
27 public class HTTPDownloader extends Downloader
28 {
29     public HTTPDownloader (Proxy proxy)
30     {
31         _proxy = proxy;
32     }
33
34     @Override protected long checkSize (Resource rsrc) throws IOException
35     {
36         URLConnection conn = ConnectionUtil.open(_proxy, rsrc.getRemote(), 0, 0);
37         try {
38             // if we're accessing our data via HTTP, we only need a HEAD request
39             if (conn instanceof HttpURLConnection) {
40                 HttpURLConnection hcon = (HttpURLConnection)conn;
41                 hcon.setRequestMethod("HEAD");
42                 hcon.connect();
43                 // make sure we got a satisfactory response code
44                 if (hcon.getResponseCode() != HttpURLConnection.HTTP_OK) {
45                     throw new IOException("Unable to check up-to-date for " +
46                                           rsrc.getRemote() + ": " + hcon.getResponseCode());
47                 }
48             }
49             return conn.getContentLength();
50
51         } finally {
52             // let it be known that we're done with this connection
53             conn.getInputStream().close();
54         }
55     }
56
57     @Override protected void download (Resource rsrc) throws IOException
58     {
59         // TODO: make FileChannel download impl (below) robust and allow apps to opt-into it via a
60         // system property
61         if (true) {
62             // download the resource from the specified URL
63             URLConnection conn = ConnectionUtil.open(_proxy, rsrc.getRemote(), 0, 0);
64             conn.connect();
65
66             // make sure we got a satisfactory response code
67             if (conn instanceof HttpURLConnection) {
68                 HttpURLConnection hcon = (HttpURLConnection)conn;
69                 if (hcon.getResponseCode() != HttpURLConnection.HTTP_OK) {
70                     throw new IOException("Unable to download resource " + rsrc.getRemote() + ": " +
71                                           hcon.getResponseCode());
72                 }
73             }
74             long actualSize = conn.getContentLength();
75             log.info("Downloading resource", "url", rsrc.getRemote(), "size", actualSize);
76             long currentSize = 0L;
77             byte[] buffer = new byte[4*4096];
78             try (InputStream in = conn.getInputStream();
79                  FileOutputStream out = new FileOutputStream(rsrc.getLocalNew())) {
80
81                 // TODO: look to see if we have a download info file
82                 // containing info on potentially partially downloaded data;
83                 // if so, use a "Range: bytes=HAVE-" header.
84
85                 // read in the file data
86                 int read;
87                 while ((read = in.read(buffer)) != -1) {
88                     // abort the download if the downloader is aborted
89                     if (_state == State.ABORTED) {
90                         break;
91                     }
92                     // write it out to our local copy
93                     out.write(buffer, 0, read);
94                     // note that we've downloaded some data
95                     currentSize += read;
96                     reportProgress(rsrc, currentSize, actualSize);
97                 }
98             }
99
100         } else {
101             log.info("Downloading resource", "url", rsrc.getRemote(), "size", "unknown");
102             File localNew = rsrc.getLocalNew();
103             try (ReadableByteChannel rbc = Channels.newChannel(rsrc.getRemote().openStream());
104                  FileOutputStream fos = new FileOutputStream(localNew)) {
105                 // TODO: more work is needed here, transferFrom can fail to transfer the entire
106                 // file, in which case it's not clear what we're supposed to do.. call it again?
107                 // will it repeatedly fail?
108                 fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
109                 reportProgress(rsrc, localNew.length(), localNew.length());
110             }
111         }
112     }
113
114     protected final Proxy _proxy;
115 }