blob: cfbb14fb78f9ac62a89311bf3f17f797bc5aeca4 [file] [log] [blame]
/*
* 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);
}
}
}