| /* |
| * Copyright (c) 2014-2017 Eike Stepper (Loehne, Germany) and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v2.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v20.html |
| * |
| * Contributors: |
| * Eike Stepper - initial API and implementation |
| */ |
| package org.eclipse.oomph.setup.util; |
| |
| import org.eclipse.oomph.setup.log.ProgressLog; |
| import org.eclipse.oomph.util.IOUtil; |
| import org.eclipse.oomph.util.OS; |
| |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.resource.ContentHandler; |
| import org.eclipse.emf.ecore.resource.URIConverter; |
| |
| import java.io.BufferedInputStream; |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.net.HttpURLConnection; |
| import java.net.SocketTimeoutException; |
| import java.net.URL; |
| import java.net.URLConnection; |
| import java.util.Collections; |
| import java.util.Map; |
| |
| /** |
| * @author Eike Stepper |
| */ |
| public final class DownloadUtil |
| { |
| private static final int RETRY_DELAY = 2000; |
| |
| private static final int HTTP_ERROR_BASE_CODE = 400; |
| |
| private static final int DOWNLOAD_TIMEOUT = 30000; |
| |
| private static final int CONNECT_TIMEOUT = 10000; |
| |
| private static final int READ_TIMEOUT = 30000; |
| |
| private static final int BUFFER_SIZE = 4096; |
| |
| private DownloadUtil() |
| { |
| } |
| |
| public static File downloadURL(String url, ProgressLog progress) |
| { |
| String normalizedURL = url.endsWith("/") ? url.substring(0, url.length() - 1) : url; |
| |
| try |
| { |
| String name = encodeFilename(url); |
| File tmp = File.createTempFile(name + "-", ".part"); |
| File file = new File(tmp.getParentFile(), name + ".zip"); |
| if (!file.exists()) |
| { |
| try |
| { |
| downloadURL(normalizedURL, tmp, progress); |
| } |
| catch (Exception ex) |
| { |
| if (tmp.exists() && !tmp.delete()) |
| { |
| tmp.deleteOnExit(); |
| } |
| |
| throw ex; |
| } |
| |
| tmp.renameTo(file); |
| } |
| |
| return file; |
| } |
| catch (RuntimeException ex) |
| { |
| throw ex; |
| } |
| catch (Exception ex) |
| { |
| throw new RuntimeException(ex); |
| } |
| } |
| |
| @SuppressWarnings("resource") |
| private static void downloadURL(String url, File file, ProgressLog progress) |
| { |
| final byte data[] = new byte[BUFFER_SIZE]; |
| BufferedInputStream in = null; |
| FileOutputStream out = null; |
| |
| try |
| { |
| SocketTimeoutException exception = null; |
| String fileName = file.getName(); |
| float factor = 0; |
| |
| long start = System.currentTimeMillis(); |
| while (System.currentTimeMillis() < start + DOWNLOAD_TIMEOUT) |
| { |
| exception = null; |
| |
| try |
| { |
| URLConnection connection = new URL(url).openConnection(); |
| connection.setConnectTimeout(CONNECT_TIMEOUT - (int)(System.currentTimeMillis() - start)); |
| connection.setReadTimeout(READ_TIMEOUT); |
| |
| if (connection instanceof HttpURLConnection) |
| { |
| connection.connect(); |
| |
| int result = ((HttpURLConnection)connection).getResponseCode(); |
| if (result >= HTTP_ERROR_BASE_CODE) |
| { |
| throw new IOException("HTTP error " + result); |
| } |
| } |
| |
| int length = connection.getContentLength(); |
| factor = 100f / length; |
| fileName = new File(connection.getURL().getFile()).getName(); |
| |
| in = new BufferedInputStream(connection.getInputStream()); |
| break; |
| } |
| catch (SocketTimeoutException ex) |
| { |
| exception = ex; |
| progress.log("Connection timed out. Retrying in 2 seconds..."); |
| |
| try |
| { |
| Thread.sleep(RETRY_DELAY); |
| } |
| catch (InterruptedException ex1) |
| { |
| throw ex; |
| } |
| } |
| } |
| |
| if (exception != null) |
| { |
| throw exception; |
| } |
| |
| out = new FileOutputStream(file); |
| |
| int lastPercent = 0; |
| int read = 0; |
| for (;;) |
| { |
| long startRead = System.currentTimeMillis(); |
| int n; |
| |
| try |
| { |
| n = in.read(data, 0, BUFFER_SIZE); |
| if (n == -1) |
| { |
| break; |
| } |
| } |
| catch (SocketTimeoutException ex) |
| { |
| progress.log("Timeout during read after " + (System.currentTimeMillis() - startRead) + " millis"); |
| throw ex; |
| } |
| |
| out.write(data, 0, n); |
| read += n; |
| |
| int percent = Math.round(factor * read); |
| if (percent != lastPercent) |
| { |
| progress.log("Downloading " + fileName + " (" + percent + "%)"); |
| } |
| } |
| } |
| catch (IOException ex) |
| { |
| throw new RuntimeException("Problem downloading '" + url + "'", ex); |
| } |
| finally |
| { |
| OS.close(out); |
| OS.close(in); |
| } |
| } |
| |
| private static String encodeFilename(String url) |
| { |
| StringBuilder builder = new StringBuilder(url); |
| for (int i = 0; i < builder.length(); i++) |
| { |
| char c = builder.charAt(i); |
| if (!(Character.isLetter(c) || Character.isDigit(c))) |
| { |
| builder.setCharAt(i, '_'); |
| } |
| } |
| |
| return builder.toString(); |
| } |
| |
| public static String load(URIConverter uriConverter, URI uri, String encoding) throws IOException |
| { |
| BufferedInputStream bufferedInputStream = null; |
| try |
| { |
| bufferedInputStream = new BufferedInputStream(uriConverter.createInputStream(uri)); |
| byte[] input = new byte[bufferedInputStream.available()]; |
| bufferedInputStream.read(input); |
| |
| if (encoding == null) |
| { |
| Map<String, ?> contentDescription = uriConverter.contentDescription(uri, |
| Collections.singletonMap(ContentHandler.OPTION_REQUESTED_PROPERTIES, Collections.singleton(ContentHandler.CONTENT_TYPE_PROPERTY))); |
| encoding = (String)contentDescription.get(ContentHandler.CHARSET_PROPERTY); |
| } |
| |
| return encoding == null ? new String(input) : new String(input, encoding); |
| } |
| finally |
| { |
| IOUtil.close(bufferedInputStream); |
| } |
| } |
| } |