/*******************************************************************************
* Copyright (c) 2014 Red Hat
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* JBoss by Red Hat
*******************************************************************************/
package org.jboss.tools.runtime.core.util.internal;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.jboss.tools.foundation.core.ecf.URLTransportUtility;
import org.jboss.tools.foundation.core.tasks.TaskModel;
import org.jboss.tools.runtime.core.RuntimeCoreActivator;
import org.jboss.tools.runtime.core.extract.ExtractUtility;
import org.jboss.tools.runtime.core.extract.IOverwrite;
import org.jboss.tools.runtime.core.model.IDownloadRuntimeWorkflowConstants;
/**
* Mixed class of core+ui to initiate the download, unzipping,
* and runtime creation for a downloaded runtime.
*/
public class DownloadRuntimeOperationUtility {
private static final String SEPARATOR = "/"; //$NON-NLS-1$
protected File getNextUnusedFilename(File destination, String name) {
String nameWithoutSuffix = null;
if( name.indexOf('.') == -1 ) {
nameWithoutSuffix = name;
} else if( name.endsWith(".tar.gz"))
nameWithoutSuffix = name.substring(0, name.length() - ".tar.gz".length());
else
nameWithoutSuffix = name.substring(0, name.lastIndexOf('.'));
String suffix = name.substring(nameWithoutSuffix.length());
int i = 1;
String tmpName = null;
File file = new File (destination, name);
while (file.exists()) {
tmpName = nameWithoutSuffix + "(" + i++ + ")" + suffix; //$NON-NLS-1$ //$NON-NLS-2$
file = new File(destination, tmpName);
}
return file;
}
/**
*
* @param downloadDestinationPath The path to put the downloaded zip
* @param urlString The remote url
* @param deleteOnExit Whether to delete on exit or not
* @return
*/
private File getDestinationFile(String downloadDestinationPath, String urlString, boolean deleteOnExit) throws CoreException {
File ret = null;
try {
URL url = new URL(urlString);
String name = url.getPath();
int slashIdx = name.lastIndexOf('/');
if (slashIdx >= 0)
name = name.substring(slashIdx + 1);
File destination = new File(downloadDestinationPath);
destination.mkdirs();
ret = new File (destination, name);
if (deleteOnExit) {
ret = getNextUnusedFilename(destination, name);
}
if( deleteOnExit )
ret.deleteOnExit();
return ret;
} catch (IOException e) {
cancel(ret);
IStatus s = new Status(IStatus.ERROR, RuntimeCoreActivator.PLUGIN_ID, e.getMessage(), e);
throw new CoreException(s);
}
}
private boolean cacheOutdated(File local, boolean deleteOnExit, long urlLastModified) {
boolean download = true;
long urlModified = 0;
if (!deleteOnExit) {
long cacheModified = local.lastModified();
download = cacheModified <= 0 || cacheModified != urlModified;
}
return download;
}
private long getRemoteURLModified(String urlString, String user, String pass, IProgressMonitor monitor) throws CoreException, IOException {
monitor.beginTask("Checking remote timestamp", 100);
long l = new URLTransportUtility().getLastModified(new URL(urlString), user, pass, monitor);
monitor.worked(100);
monitor.done();
return l;
}
private void validateInputs(String downloadDirectoryPath, String unzipDirectoryPath) throws CoreException {
File downloadDirectory = new File(downloadDirectoryPath);
downloadDirectory.mkdirs();
if (!downloadDirectory.isDirectory()) {
throw new CoreException(new Status(IStatus.ERROR, RuntimeCoreActivator.PLUGIN_ID, "The '" + downloadDirectory + "' is not a directory.")); //$NON-NLS-1$ //$NON-NLS-2$
}
File unzipDirectory = new File(unzipDirectoryPath);
unzipDirectory.mkdirs();
if (!unzipDirectory.isDirectory()) {
throw new CoreException( new Status(IStatus.ERROR, RuntimeCoreActivator.PLUGIN_ID, "The '" + unzipDirectory + "' is not a directory.")); //$NON-NLS-1$ //$NON-NLS-2$
}
}
public File download(String unzipDirectoryPath, String downloadDirectoryPath,
String urlString, boolean deleteOnExit, String user, String pass, TaskModel tm, IProgressMonitor monitor) throws CoreException {
monitor.beginTask("Download runtime from url " + urlString, 500);
try {
validateInputs(downloadDirectoryPath, unzipDirectoryPath);
File downloadedFile = downloadRemoteRuntime(unzipDirectoryPath, downloadDirectoryPath,
urlString, deleteOnExit, user, pass, new SubProgressMonitor(monitor, 500));
return downloadedFile;
} finally {
monitor.done();
}
}
public IStatus downloadAndUnzip(String unzipDirectoryPath, String downloadDirectoryPath,
String urlString, boolean deleteOnExit, String user, String pass, TaskModel tm, IProgressMonitor monitor) {
monitor.beginTask("Configuring runtime from url " + urlString, 500);
try {
validateInputs(downloadDirectoryPath, unzipDirectoryPath);
File downloadedFile = downloadRemoteRuntime(unzipDirectoryPath, downloadDirectoryPath, urlString, deleteOnExit, user, pass, new SubProgressMonitor(monitor, 450));
ExtractUtility extractUtil = new ExtractUtility(downloadedFile);
IOverwrite ow = (IOverwrite)tm.getObject(IDownloadRuntimeWorkflowConstants.OVERWRITE);
if( ow == null ) {
ow = createOverwriteFileQuery();
}
unzip(extractUtil, downloadedFile, unzipDirectoryPath, ow, new SubProgressMonitor(monitor, 30));
String updatedRuntimeRoot = getUpdatedUnzipPath(extractUtil, unzipDirectoryPath, new SubProgressMonitor(monitor, 10));
tm.putObject(IDownloadRuntimeWorkflowConstants.UNZIPPED_SERVER_HOME_DIRECTORY, updatedRuntimeRoot);
} catch(CoreException ce) {
return ce.getStatus();
} finally {
monitor.done();
}
return Status.OK_STATUS;
}
private File downloadRemoteRuntime(String unzipDirectoryPath, String destinationDirectory,
String urlString, boolean deleteOnExit, String user, String pass, IProgressMonitor monitor) throws CoreException {
monitor.beginTask("Downloading " + urlString, 1000);
File file = null;
try {
file = getDestinationFile(destinationDirectory, urlString, deleteOnExit);
long urlModified = 0;
if( !deleteOnExit ) {
try {
urlModified = getRemoteURLModified(urlString, user, pass, new SubProgressMonitor(monitor, 100));
} catch(IOException ioe) {
// Ignore error on checking timestamp, may be fluke
} catch(CoreException ce) {
// Ignore error on checking timestamp, may be fluke
}
}
boolean download = cacheOutdated(file, deleteOnExit, urlModified);
IStatus result = null;
if (download) {
result = downloadFileFromRemoteUrl(file, new URL(urlString), urlModified, user, pass, new SubProgressMonitor(monitor, 900));
}
if( !result.isOK())
throw new CoreException(result);
if (monitor.isCanceled())
throw new CoreException(cancel(file));
return file;
} catch (IOException e) {
cancel(file);
throw new CoreException(new Status(IStatus.ERROR, RuntimeCoreActivator.PLUGIN_ID, e.getMessage(), e));
} finally {
monitor.done();
}
}
private void unzip(ExtractUtility util, File downloadedFile, String unzipDirectoryPath, IOverwrite overwriteQuery, IProgressMonitor monitor) throws CoreException {
monitor.beginTask("Unzipping " + downloadedFile.getAbsolutePath(), 1000);
if (monitor.isCanceled())
throw new CoreException(cancel(downloadedFile));
final IStatus status = util.extract(new File(unzipDirectoryPath), overwriteQuery, new SubProgressMonitor(monitor, 1000));
if (monitor.isCanceled())
throw new CoreException( cancel(downloadedFile));
if( !status.isOK())
throw new CoreException(status);
}
private IStatus cancel(File f) {
if( f != null ) {
f.deleteOnExit();
f.delete();
}
return Status.CANCEL_STATUS;
}
private IOverwrite createOverwriteFileQuery() {
return new IOverwrite() {
public int overwrite(File file) {
return IOverwrite.YES;
}
};
}
private String getUpdatedUnzipPath(ExtractUtility util, String unzipDirectoryPath, IProgressMonitor monitor) throws CoreException {
try {
String root = util.getExtractedRootFolder( new SubProgressMonitor(monitor, 10));
if (root != null) {
File rootFile = new File(unzipDirectoryPath, root);
if (rootFile != null && rootFile.exists()) {
unzipDirectoryPath = rootFile.getAbsolutePath();
}
}
return unzipDirectoryPath;
} catch(CoreException ce) {
cancel(util.getOriginalFile());
throw ce;
} finally {
monitor.done();
}
}
private IStatus downloadFileFromRemoteUrl(File toFile, URL url, long remoteUrlModified, String user, String pass, IProgressMonitor monitor) throws IOException {
OutputStream out = null;
try {
out = new BufferedOutputStream(new FileOutputStream(toFile));
IStatus result = new URLTransportUtility().download(
toFile.getName(), url.toExternalForm(), user, pass, out, -1, monitor);
out.flush();
out.close();
if (remoteUrlModified > 0) {
toFile.setLastModified(remoteUrlModified);
}
return result;
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
// ignore
}
}
}
}
}