/******************************************************************************* * Copyright (c) 2012 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.tests.util; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import org.eclipse.core.runtime.CoreException; import org.springsource.ide.eclipse.commons.core.HttpUtil; /** * Manages a cache of downloaded files used by tests. * * @author Kris De Volder, Steffen Pingel * * @since 2.8 */ public class DownloadManager { /** * An instance of this interface represent an action to execute on a downloaded * File. The action may indicate failure by throwing an exception or by * returning false. A failed action may trigger the DownloadManager to * clear the cache and try again for a limited number of times. */ public interface DownloadRequestor { void exec(File downloadedFile) throws Exception; } private final String cacheDirectory; private static DownloadManager defaultInstance = null; public static DownloadManager getDefault() { if (defaultInstance==null) { defaultInstance = new DownloadManager(); } return defaultInstance; } public DownloadManager() { this(System.getProperty( "com.springsource.sts.tests.cache", System.getProperty("user.home") + File.separatorChar + ".sts-test-cache")); deleteBuildSnapshots(); } /** * Build snapshots from a previous test run shouldn't be used from the cache. So delete them * when the DownloadManager instance is created. */ private void deleteBuildSnapshots() { //Only do this on the build site, locally it is easy enough to delete buildsnaps manually // as needed/desired. if (StsTestUtil.isOnBuildSite()) { File cache = new File(cacheDirectory); if (cache.isDirectory()) { String[] names = cache.list(); for (String name : names) { if (name.contains("SNAPSHOT")) { try { new File(cache, name).delete(); } catch (Throwable e) { e.printStackTrace(); } } } } } } public DownloadManager(String cacheDir) { this.cacheDirectory = cacheDir; } /** * This method is deprecated, please use doWithDownload to provide proper recovery * for cache corruption. */ @Deprecated public File downloadFile(URI uri) throws URISyntaxException, FileNotFoundException, CoreException, IOException { String protocol = uri.getScheme(); if ("file".equals(protocol)) { return new File(uri); } String path = uri.getPath(); int i = path.lastIndexOf("/"); if (i >= 0) { path = path.substring(i + 1); } File target = new File(cacheDirectory, path); if (target.exists()) { return target; } File cache = new File(cacheDirectory); if (!cache.exists()) { cache.mkdirs(); } File targetPart = new File(cache, path + ".part"); FileOutputStream out = new FileOutputStream(targetPart); try { System.out.println("Downloading " + uri + " to " + target); HttpUtil.download(uri, out, null); } finally { out.close(); } if (!targetPart.renameTo(target)) { throw new IOException("Error while renaming " + targetPart + " to " + target); } return target; } /** * This method tries to download or fetch a File from the cache, then passes the * downloaded file to the DownloadRequestor. * <p> * If the requestor fails to properly execute on the downloaded file, the cache * will be presumed to be corrupt. The file will be deleted from the cache * and the download will be tried again. (for a limited number of times) */ public void doWithDownload(URI target, DownloadRequestor action) throws Exception { int tries = 4; // try at most X times Exception e = null; File downloadedFile = null; do { tries--; try { downloadedFile = downloadFile(target); action.exec(downloadedFile); return; // action and download succeeded without exceptions } catch (Exception caught) { caught.printStackTrace(); //Presume the cache may be corrupt! System.out.println("Delete corrupt download: "+downloadedFile); //downloaded file may be null if download failed, rather than its processing: if (downloadedFile!=null) { downloadedFile.delete(); } e = caught; } } while (tries>0); //Can only get here if action or download failed... //thus, e can not be null. throw e; } public File getCacheDir() { return new File(cacheDirectory); } }