/*******************************************************************************
* Copyright (c) 2013 GoPivotal, Inc.
* 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:
* GoPivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.boot.core.cli.install;
import java.io.File;
import java.net.URL;
import org.apache.commons.io.FileUtils;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.springframework.ide.eclipse.boot.core.BootActivator;
import org.springsource.ide.eclipse.commons.core.ZipFileUtil;
import org.springsource.ide.eclipse.commons.frameworks.core.ExceptionUtil;
import org.springsource.ide.eclipse.commons.frameworks.core.downloadmanager.DownloadManager;
import org.springsource.ide.eclipse.commons.frameworks.core.downloadmanager.DownloadManager.DownloadRequestor;
import org.springsource.ide.eclipse.commons.frameworks.core.downloadmanager.DownloadableItem;
import org.springsource.ide.eclipse.commons.frameworks.core.downloadmanager.UIThreadDownloadDisallowed;
/**
* A Boot Installation that is located in a zip file. It must be unzipped locally
* before it can be used.
* <p>
* This class takes care of downloading and unzipping it automatically to to
* cache directory located in the workspace.
*
* @author Kris De Volder
*/
public class ZippedBootInstall extends BootInstall {
/**
* TODO: DownloadableZipItem should probably be moved to commons
* (same place as DownloadableItem).
*/
public class DownloadableZipItem extends DownloadableItem {
private String fileName; //Cached value for getFileName method.
public DownloadableZipItem(URL url, DownloadManager downloader) {
super(url, downloader);
}
@Override
protected String getFileName() {
if (fileName==null) {
try {
//Try to create human friendly name
String name = new Path(getURL().getPath()).lastSegment();
if (name!=null && name.endsWith(".zip")) {
fileName = name;
}
} catch (Throwable e) {
BootActivator.log(e);
}
//Ensure that filename is at least set to something that ends with .zip
if (fileName==null) {
fileName = super.getFileName()+".zip";
}
}
return fileName;
}
private synchronized void unzip(File zipFile, File unzipDir) throws Exception {
if (unzipDir.exists()) {
//Already unzipped by someone else.
return;
}
try {
ZipFileUtil.unzip(zipFile, unzipDir, null);
return;
} catch (Throwable e) {
//If operation has an error or was aborted the unzipDir must be deleted because its probably junk.
// data in it may not be valid.
FileUtils.deleteQuietly(unzipDir);
throw ExceptionUtil.exception(e);
}
}
/**
* Force the item to be downloaded and unzipped locally. If an item is already downloaded
* the cached local file will be returned immediately. Otherwise the method will block
* until the download is complete or an error occurs.
* <p>
* The returned file will point to the location where the zipfile was expanded to.
*/
public File getFile() throws Exception {
try {
final File[] fileBox = new File[1];
downloader.doWithDownload(this, new DownloadRequestor() {
public void exec(File zipFile) throws Exception {
File unzipDir = getUnzipDir();
unzip(zipFile, unzipDir);
fileBox[0] = unzipDir;
}
});
downloadStatus = Status.OK_STATUS;
return fileBox[0];
} catch (UIThreadDownloadDisallowed e) {
//Shouldn't affect download status since it means download was not attempted
throw e;
} catch (Exception e) {
downloadStatus = error(ExceptionUtil.getMessage(e));
throw e;
}
}
@Override
public void clearCache() {
synchronized (downloader) {
super.clearCache();
File unzipDir = zip.getUnzipDir();
FileUtils.deleteQuietly(unzipDir);
}
}
}
private DownloadableItem zip;
private File home; //Will be set once the install is unzipped and ready for use.
public ZippedBootInstall(DownloadManager downloader, String uri, String name) throws Exception {
super(uri, name);
this.zip = new DownloadableZipItem(new URL(uri), downloader);
}
@Override
public File getHome() throws Exception {
if (home==null) {
File unzipped = zip.getFile();
//Assumes that unzipped will contain one directory 'spring-<version>'
for (File dir : unzipped.listFiles()) {
if (dir.isDirectory()) {
String name = dir.getName();
if (name.startsWith("spring-")) {
home = dir;
}
}
}
}
return home;
}
@Override
public String getUrl() {
return uriString;
}
@Override
protected boolean mayRequireDownload() {
//We can do better than just looking at the url (as the super method does).
//We can see whether or not the zip file was dowloaded already or not.
if (zip!=null) {
return !zip.isDownloaded();
} else {
return super.mayRequireDownload();
}
}
@Override
public void clearCache() {
if (zip!=null) {
zip.clearCache();
}
}
}