/******************************************************************************* * Copyright (c) 2013 Pivotal Software, 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: * Pivotal Software, Inc. - initial API and implementation *******************************************************************************/ package org.springsource.ide.eclipse.commons.frameworks.core.downloadmanager; import java.io.File; import java.net.URL; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import org.apache.commons.codec.binary.Base64; import org.apache.commons.io.FileUtils; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.springsource.ide.eclipse.commons.frameworks.core.ExceptionUtil; import org.springsource.ide.eclipse.commons.frameworks.core.FrameworkCoreActivator; import org.springsource.ide.eclipse.commons.frameworks.core.downloadmanager.DownloadManager.DownloadRequestor; /** * A DownloadableItem is something that can be downloaded and * stored in the local file system as a file. * * @author Kris De Volder */ public class DownloadableItem { private final URL url; protected final DownloadManager downloader; private String name; //optional name. If set this name will be used as filename in the cache otherwise // suitable name will be computed. protected IStatus downloadStatus = Status.OK_STATUS; //error message if download failed. Otherwise contains 'OK'. public DownloadableItem(URL url, DownloadManager downloader) { this.url = url; this.downloader = downloader; } public void setFileName(String n) { this.name = n; } /** * A downloadable item must provide a URI where its contents can be fetched from. */ public URL getURL() { return url; } /** * Force the item to be downloaded to a local File. 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. */ public File getFile() throws Exception { try { final File[] fileBox = new File[1]; downloader.doWithDownload(this, new DownloadRequestor() { public void exec(File downloadedFile) throws Exception { fileBox[0] = downloadedFile; //TODO; validate file contents? } }); 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; } } protected IStatus error(String message) { return new Status(IStatus.ERROR, FrameworkCoreActivator.PLUGIN_ID, message); } /** * A downloadable item must provide a filename where its cached downloaded contents * should be stored. The name must uniquely identify the downloadable item * within the scope of the DownloadManager used to download this item. * <p> * The name must also be a legal file name on the current OS. * <p> * A default implementation is provided that uses sha1 and Base64 encoding * to generate a name from the uri. * <p> * These generated names are not guaranteed to be unique, but the chance of * a collisions is astronomically small. */ protected String getFileName() { if (name==null) { try { MessageDigest sha1encoder = MessageDigest.getInstance("sha1"); byte[] bytes = sha1encoder.digest((""+getURL()).getBytes()); name = new String(Base64.encodeBase64(bytes)); name = name.replace('/', '_'); //slashes are trouble in file names. } catch (NoSuchAlgorithmException e) { //This should not be possible throw new Error(e); } } return name; } @Override public String toString() { return url.toString(); } public boolean isDownloaded() { return downloader!=null && downloader.isDownloaded(this); } /** * Error message if download failed. Other * @return */ public IStatus getDownloadStatus() { return downloadStatus; } public void clearCache() { //Take care not to delete the original file if was local to begin with (in that case we don't // copy it into the cache dir so there is no cache to clear! if (url!=null && !"file".equals(url.getProtocol())) { //Avoid race conditions when someone is downloading this item at the moment. synchronized (downloader) { File localFile = downloader.getLocalLocation(this); FileUtils.deleteQuietly(localFile); } } } /** * Determine the location to unzip to (without actually doing any unzipping). */ public File getUnzipDir() { String fileName = getFileName(); Assert.isTrue(fileName.endsWith(".zip")); File unzipLocation = new File(downloader.getCacheDir(), fileName.substring(0, fileName.length()-4)); return unzipLocation; } }