/******************************************************************************* * Copyright (c) 2006-2013, Cloudsmith Inc. * The code, documentation and other materials contained herein have been * licensed under the Eclipse Public License - v 1.0 by the copyright holder * listed above, as the Initial Contributor under such license. The text of * such license is available at www.eclipse.org. ******************************************************************************/ package org.eclipse.buckminster.download; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.buckminster.download.internal.Activator; import org.eclipse.buckminster.runtime.BuckminsterException; import org.eclipse.buckminster.runtime.IOUtils; import org.eclipse.buckminster.runtime.MonitorUtils; import org.eclipse.buckminster.runtime.NullOutputStream; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Platform; import org.eclipse.ecf.core.util.StringUtils; import org.eclipse.osgi.util.NLS; /** * @author Thomas Hallgren * @author Guillaume CHATELET * */ public class Installer { private static final HashMap<String, Installer> decompressorCache = new HashMap<String, Installer>(); private static final HashMap<String, Installer> installerCache = new HashMap<String, Installer>(); private static final Installer plainInstaller = new Installer(null, null); public static Installer getInstaller(final String fileName, boolean expand) throws CoreException { synchronized (installerCache) { Map<String, Installer> cache = expand ? installerCache : decompressorCache; for (Map.Entry<String, Installer> entry : cache.entrySet()) { if (fileName.endsWith(entry.getKey())) return entry.getValue(); } IExtensionRegistry extRegistry = Platform.getExtensionRegistry(); IConfigurationElement[] elems = extRegistry.getConfigurationElementsFor(Activator.DECOMPRESSORS_POINT); int idx = elems.length; String[][] suffixes = new String[idx][]; while (--idx >= 0) suffixes[idx] = StringUtils.split(elems[idx].getAttribute("suffixes"), ','); //$NON-NLS-1$ ArrayList<IDecompressor> decompressorList = null; String chewedName = fileName; while (chewedName.length() > 0) { // Find the suffix that matches the most characters at the // end of the path // int matchIdx = -1; int matchLen = -1; idx = elems.length; suffixFound: while (--idx >= 0) { for (String suffix : suffixes[idx]) { if (suffix.length() > matchLen && chewedName.endsWith(suffix)) { matchLen = suffix.length(); matchIdx = idx; break suffixFound; } } } if (matchIdx < 0) break; if (decompressorList == null) decompressorList = new ArrayList<IDecompressor>(); IConfigurationElement elem = elems[matchIdx]; decompressorList.add(IDecompressor.class.cast(elem.createExecutableExtension("class"))); //$NON-NLS-1$ // Strip of suffix managed by this decompressor // chewedName = chewedName.substring(0, chewedName.length() - matchLen); } IExpander expander = null; if (expand) { elems = extRegistry.getConfigurationElementsFor(Activator.EXPANDERS_POINT); idx = elems.length; suffixes = new String[idx][]; while (--idx >= 0) suffixes[idx] = StringUtils.split(elems[idx].getAttribute("suffixes"), ','); //$NON-NLS-1$ // Find the suffix that matches the most characters at the // end of the path // int matchIdx = -1; int matchLen = -1; idx = elems.length; suffixFound: while (--idx >= 0) { for (String suffix : suffixes[idx]) { if (suffix.length() > matchLen && chewedName.endsWith(suffix)) { matchLen = suffix.length(); matchIdx = idx; break suffixFound; } } } if (matchIdx >= 0) { chewedName = chewedName.substring(0, chewedName.length() - matchLen); expander = IExpander.class.cast(elems[matchIdx].createExecutableExtension("class")); //$NON-NLS-1$ } } if (decompressorList == null && expander == null) { int lastDot = fileName.lastIndexOf('.'); if (lastDot >= 0 && lastDot < fileName.length() - 1 && Character.isLetter(fileName.charAt(lastDot + 1))) // // Assume that this suffix will never render anything // but the plain installer from now on // cache.put(fileName.substring(lastDot), plainInstaller); return plainInstaller; } String fullSuffixMatch = fileName.substring(chewedName.length()); Installer validator = new Installer(decompressorList, expander); cache.put(fullSuffixMatch, validator); return validator; } } public static Installer getPlainInstaller() { return plainInstaller; } private final List<IDecompressor> decompressors; private final IExpander expander; private Installer(List<IDecompressor> decompressors, IExpander expander) { this.decompressors = (decompressors == null) ? Collections.<IDecompressor> emptyList() : decompressors; this.expander = expander; } public void install(InputStream input, File destination, FileFilter fileFilter, boolean flattenHierarchy, IProgressMonitor monitor) throws IOException, CoreException { int dcCount = decompressors.size(); MonitorUtils.begin(monitor, 100 + dcCount * 100); if (dcCount > 0) { // We will want to close our IDecompressor instances // later on but we don't want to close the input that // was passed in. So we protect it here. // input = new FilterInputStream(input) { @Override public void close() { } }; for (IDecompressor decompressor : decompressors) input = decompressor.decompress(input, MonitorUtils.subMonitor(monitor, 100)); } try { IProgressMonitor subMon = MonitorUtils.subMonitor(monitor, 100); if (expander != null) { expander.setFilter(fileFilter); expander.setFlattenHierarchy(flattenHierarchy); expander.expand(input, destination, subMon); } else { // Just verify that the stream can be read // OutputStream output = null; try { if (destination == null) output = NullOutputStream.INSTANCE; else { File parentFolder = destination.getParentFile(); if (!(parentFolder == null || parentFolder.isDirectory() || parentFolder.mkdirs())) throw BuckminsterException.fromMessage(NLS.bind(Messages.unable_to_access_directory_0, parentFolder)); output = new FileOutputStream(destination); } IOUtils.copy(input, output, subMon); } finally { IOUtils.close(output); } MonitorUtils.done(subMon); } } finally { if (dcCount > 0) IOUtils.close(input); MonitorUtils.done(monitor); } } public void install(InputStream input, File destination, IProgressMonitor monitor) throws IOException, CoreException { install(input, destination, null, false, monitor); } public void validate(File file, IProgressMonitor monitor) throws CoreException { if (decompressors.size() == 0 && expander == null) return; InputStream input = null; try { input = new FileInputStream(file); install(input, null, monitor); } catch (IOException e) { throw BuckminsterException.wrap(e); } finally { IOUtils.close(input); } } }