]> gitweb.fperrin.net Git - GpsPrune.git/blob - src/tim/prune/function/srtm/DownloadSrtmFunction.java
Use SRTM 1deg data from NASA servers
[GpsPrune.git] / src / tim / prune / function / srtm / DownloadSrtmFunction.java
1 package tim.prune.function.srtm;
2
3 import java.io.File;
4 import java.io.FileOutputStream;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.net.CookieHandler;
8 import java.net.CookieManager;
9 import java.net.CookiePolicy;
10 import java.net.URL;
11 import java.net.HttpURLConnection;
12 import java.util.ArrayList;
13 import java.util.Base64;
14
15 import javax.swing.JOptionPane;
16
17 import tim.prune.App;
18 import tim.prune.GenericFunction;
19 import tim.prune.GpsPrune;
20 import tim.prune.I18nManager;
21 import tim.prune.config.Config;
22 import tim.prune.data.DoubleRange;
23 import tim.prune.gui.ProgressDialog;
24
25 /**
26  * Class to provide a download function for the Space Shuttle's SRTM data files.
27  * HGT files are downloaded into memory via HTTP and stored in the map cache.
28  */
29 public class DownloadSrtmFunction extends GenericFunction implements Runnable
30 {
31         /** Progress dialog */
32         private ProgressDialog _progress = null;
33         /** Flag to check whether this function is currently running or not */
34         private boolean _running = false;
35
36
37         /**
38          * Constructor
39          * @param inApp  App object
40          */
41         public DownloadSrtmFunction(App inApp) {
42                 super(inApp);
43
44                 CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
45
46         }
47
48         /** @return name key */
49         public String getNameKey() {
50                 return "function.downloadsrtm";
51         }
52
53         /**
54          * Begin the download
55          */
56         public void begin()
57         {
58                 _running = true;
59                 if (_progress == null) {
60                         _progress = new ProgressDialog(_parentFrame, getNameKey());
61                 }
62                 _progress.show();
63                 // start new thread for time-consuming part
64                 new Thread(this).start();
65         }
66
67         /**
68          * Run method using separate thread
69          */
70         public void run()
71         {
72                 // Compile list of tiles to get
73                 ArrayList<SrtmTile> tileList = new ArrayList<SrtmTile>();
74
75                 // First, loop to see which tiles are needed
76                 DoubleRange lonRange = _app.getTrackInfo().getTrack().getLonRange();
77                 DoubleRange latRange = _app.getTrackInfo().getTrack().getLatRange();
78                 final int minLon = (int) Math.floor(lonRange.getMinimum());
79                 final int maxLon = (int) Math.floor(lonRange.getMaximum());
80                 final int minLat = (int) Math.floor(latRange.getMinimum());
81                 final int maxLat = (int) Math.floor(latRange.getMaximum());
82
83                 for (int lon=minLon; lon<= maxLon; lon++)
84                 {
85                         for (int lat=minLat; lat <= maxLat; lat++)
86                         {
87                                 SrtmTile tile = new SrtmTile(lat, lon);
88                                 boolean alreadyGot = false;
89                                 for (int t = 0; t < tileList.size(); t++)
90                                 {
91                                         if (tileList.get(t).equals(tile)) {
92                                                 alreadyGot = true;
93                                         }
94                                 }
95                                 if (!alreadyGot) {tileList.add(tile);}
96                         }
97                 }
98
99                 downloadTiles(tileList);
100                 // Finished
101                 _running = false;
102         }
103
104
105         /**
106          * Download the tiles of SRTM data
107          * @param inTileList list of tiles to get
108          */
109         private void downloadTiles(ArrayList<SrtmTile> inTileList)
110         {
111                 // Update progress bar
112                 if (_progress != null)
113                 {
114                         // advance by 1 for HTTP connection open, then by 1 for every tenth of the download
115                         _progress.setMaximum(inTileList.size() * 11);
116                         _progress.setValue(0);
117                 }
118
119                 String errorMessage = null;
120
121                 // Check the cache is ok
122                 final String diskCachePath = Config.getConfigString(Config.KEY_DISK_CACHE);
123                 if (diskCachePath != null)
124                 {
125                         File srtmDir = new File(diskCachePath, "srtm");
126                         if (!srtmDir.exists() && !srtmDir.mkdir()) {
127                                 // can't create the srtm directory
128                                 errorMessage = I18nManager.getText("error.downloadsrtm.nocache");
129                         }
130                 }
131                 else {
132                         // no cache set up
133                         errorMessage = I18nManager.getText("error.downloadsrtm.nocache");
134                 }
135
136                 // Get urls for each tile
137                 URL[] urls = TileFinder.getUrls(inTileList);
138                 int numDownloaded = 0;
139                 for (int t=0; t<inTileList.size() && !_progress.isCancelled(); t++)
140                 {
141                         if (urls[t] != null)
142                         {
143                                 // Define streams
144                                 FileOutputStream outStream = null;
145                                 InputStream inStream = null;
146                                 try
147                                 {
148                                         // Set progress
149                                         _progress.setValue(t * 10);
150                                         // See if we've already got this tile or not
151                                         File outputFile = getFileToWrite(urls[t]);
152                                         if (outputFile != null)
153                                         {
154                                                 int redirects = 5;
155                                                 System.out.println("Download: Need to download: " + urls[t]);
156                                                 HttpURLConnection conn = (HttpURLConnection) urls[t].openConnection();
157                                                 String auth = "Basic " + Base64.getEncoder().encodeToString(urls[t].getUserInfo().getBytes());
158                                                 long fileLength = 0L;
159
160                                                 while (redirects > 0) {
161                                                         redirects--;
162
163                                                         conn.setRequestProperty("User-Agent", "GpsPrune v" + GpsPrune.VERSION_NUMBER);
164                                                         conn.setRequestProperty("Authorization", auth);
165                                                         conn.setInstanceFollowRedirects(false);
166                                                         conn.setUseCaches(false);
167
168                                                         int status = conn.getResponseCode();
169                                                         if (status == 200)
170                                                         {
171                                                                 inStream = conn.getInputStream();
172                                                                 fileLength = conn.getContentLengthLong();
173                                                                 break;
174                                                         }
175                                                         else if (status == 302)
176                                                         {
177                                                                 // redirected to SSO server then back to original resource
178                                                                 String newUrl = conn.getHeaderField("Location");
179                                                                 conn = (HttpURLConnection) (new URL(newUrl)).openConnection();
180                                                         }
181                                                         else
182                                                         {
183                                                                 throw new IOException("Invalid response from server: " +status+conn.getContent());
184                                                         }
185                                                 }
186                                                 _progress.setValue(t * 10 + 1);
187                                                 outStream = new FileOutputStream(outputFile);
188
189                                                 // Copy all the bytes to the file
190                                                 int c;
191                                                 long written = 0L;
192                                                 while ((c = inStream.read()) != -1)
193                                                 {
194                                                         outStream.write(c);
195                                                         written++;
196                                                         _progress.setValue(t * 10 + 1 + (int) ((10 * written) / fileLength));
197                                                 }
198
199                                                 numDownloaded++;
200                                         }
201                                         else System.out.println("Don't need to download: " + urls[t].getFile());
202                                 }
203                                 catch (IOException ioe) {errorMessage = ioe.getClass().getName() + " - " + ioe.getMessage();
204                                 }
205                                 // Make sure streams are closed
206                                 try {inStream.close();} catch (Exception e) {}
207                                 try {outStream.close();} catch (Exception e) {}
208                         }
209                 }
210
211                 _progress.dispose();
212                 if (_progress.isCancelled()) {
213                         return;
214                 }
215
216                 if (errorMessage != null) {
217                         _app.showErrorMessageNoLookup(getNameKey(), errorMessage);
218                 }
219                 else if (numDownloaded == 1)
220                 {
221                         JOptionPane.showMessageDialog(_parentFrame, I18nManager.getTextWithNumber("confirm.downloadsrtm.1", numDownloaded),
222                                 I18nManager.getText(getNameKey()), JOptionPane.INFORMATION_MESSAGE);
223                 }
224                 else if (numDownloaded > 1)
225                 {
226                         JOptionPane.showMessageDialog(_parentFrame, I18nManager.getTextWithNumber("confirm.downloadsrtm", numDownloaded),
227                                 I18nManager.getText(getNameKey()), JOptionPane.INFORMATION_MESSAGE);
228                 }
229                 else if (inTileList.size() > 0) {
230                         _app.showErrorMessage(getNameKey(), "confirm.downloadsrtm.none");
231                 }
232         }
233
234         /**
235          * See whether the SRTM file is already available locally
236          * @param inUrl URL for online resource
237          * @return file object to write to, or null if already there
238          */
239         private static File getFileToWrite(URL inUrl)
240         {
241                 String diskCachePath = Config.getConfigString(Config.KEY_DISK_CACHE);
242                 if (diskCachePath != null)
243                 {
244                         File srtmDir = new File(diskCachePath, "srtm");
245                         if (srtmDir.exists() && srtmDir.isDirectory() && srtmDir.canRead())
246                         {
247                                 File srtmFile = new File(srtmDir, new File(inUrl.getFile()).getName());
248                                 if (!srtmFile.exists() || !srtmFile.canRead() || srtmFile.length() <= 400) {
249                                         return srtmFile;
250                                 }
251                         }
252                 }
253                 return null;
254         }
255
256         /**
257          * @return true if a thread is currently running
258          */
259         public boolean isRunning()
260         {
261                 return _running;
262         }
263 }