/******************************************************************************* * Copyright (c) 2004, 2006 * Thomas Hallgren, Kenneth Olwing, Mitch Sonies * Pontus Rydin, Nils Unden, Peer Torngren * The code, documentation and other materials contained herein have been * licensed under the Eclipse Public License - v 1.0 by the individual * copyright holders listed above, as Initial Contributors under such license. * The text of such license is available at www.eclipse.org. *******************************************************************************/ package org.eclipse.buckminster.pde.internal; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FilenameFilter; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import org.eclipse.buckminster.core.metadata.MissingComponentException; import org.eclipse.buckminster.core.reader.AbstractCatalogReader; import org.eclipse.buckminster.core.reader.IReaderType; import org.eclipse.buckminster.core.reader.IStreamConsumer; import org.eclipse.buckminster.core.rmap.model.MalformedProviderURIException; import org.eclipse.buckminster.core.version.ProviderMatch; import org.eclipse.buckminster.core.version.VersionHelper; import org.eclipse.buckminster.pde.Messages; import org.eclipse.buckminster.runtime.BuckminsterException; import org.eclipse.buckminster.runtime.IOUtils; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.equinox.frameworkadmin.BundleInfo; import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.equinox.p2.metadata.VersionRange; import org.eclipse.pde.core.IModel; import org.eclipse.pde.core.plugin.IPluginModelBase; import org.eclipse.pde.internal.core.ifeature.IFeatureModel; /** * A Reader that knows about features and plugins that are part of an Eclipse * installation. * * @author Thomas Hallgren */ @SuppressWarnings("restriction") public class EclipsePlatformReader extends AbstractCatalogReader { public enum InstalledType { FEATURE, PLUGIN } /** * A File filter and collector that will collect all occurances of a named * component along with its version number. */ class PluginFilter implements FilenameFilter { private final ArrayList<Version> collector; private final Pattern pattern; PluginFilter(String componentName, ArrayList<Version> collector) { this.pattern = Pattern.compile('^' + Pattern.quote(componentName) + "_(.*?)(?:\\.jar)?$"); //$NON-NLS-1$ this.collector = collector; } @Override public boolean accept(File directory, String pathname) { Matcher m = pattern.matcher(pathname); if (!m.matches()) return false; try { collector.add(Version.parseVersion(m.group(1))); return true; } catch (IllegalArgumentException e) { return false; } } } private final String componentName; private IModel model; private BundleInfo bundle; private final InstalledType type; public EclipsePlatformReader(IReaderType readerType, ProviderMatch rInfo) throws CoreException { super(readerType, rInfo); String uri = rInfo.getRepositoryURI(); IPath path = new Path(uri); if (path.segmentCount() == 2) { type = InstalledType.valueOf(path.segment(0).toUpperCase(Locale.ENGLISH)); if (type != null) { componentName = path.segment(1); return; } } throw new MalformedProviderURIException(readerType, uri); } @Override public boolean canMaterialize() { return false; } public synchronized BundleInfo getBundleInfo() throws CoreException { if (type != InstalledType.PLUGIN) throw new IllegalStateException(Messages.plugin_requested_from_feature_reader); if (bundle == null) { bundle = getBestBundle(); if (bundle == null) throw new MissingComponentException(componentName); } return bundle; } public synchronized IFeatureModel getFeatureModel() { if (type != InstalledType.FEATURE) return null; if (model == null) model = getBestFeature(); return (IFeatureModel) model; } @Override public File getLocation() throws CoreException { File installLocation; if (type == InstalledType.PLUGIN) { BundleInfo pluginModel; try { pluginModel = getBundleInfo(); } catch (IllegalStateException e) { return null; } installLocation = EclipsePlatformReaderType.getBundleLocation(pluginModel); } else { IFeatureModel featureModel = getFeatureModel(); if (featureModel == null) return null; installLocation = new File(featureModel.getInstallLocation()); } return installLocation; } public synchronized IPluginModelBase getPluginModelBase() throws CoreException { if (type != InstalledType.PLUGIN) throw new IllegalStateException(Messages.plugin_requested_from_feature_reader); if (model == null) { model = getBestPlugin(); if (model == null) throw new MissingComponentException(componentName); } return (IPluginModelBase) model; } public InstalledType getType() { return type; } /** * This method should never be called. If a user wants to materialize an * installed plugin, that should be done using the import plugin wizard. */ @Override public void innerMaterialize(IPath destination, IProgressMonitor monitor) { throw new UnsupportedOperationException("checkout"); //$NON-NLS-1$ } @Override public boolean isFileSystemReader() { return true; } protected String getResolvedFile(String relativeFile, InputStream[] isReturn) throws IOException, CoreException { File modelRoot = getLocation(); if (modelRoot == null) throw new FileNotFoundException(relativeFile); String fileName; if (modelRoot.isDirectory()) { File wantedFile = new File(modelRoot, relativeFile); fileName = wantedFile.toString(); if (!wantedFile.exists()) throw new FileNotFoundException(fileName); if (isReturn != null) isReturn[0] = new FileInputStream(wantedFile); } else { if (!modelRoot.getName().endsWith(".jar")) //$NON-NLS-1$ throw new FileNotFoundException(modelRoot.toString()); fileName = modelRoot.getName() + '!' + relativeFile; final JarFile jf = new JarFile(modelRoot); JarEntry entry = jf.getJarEntry(relativeFile); if (entry == null) { jf.close(); throw new FileNotFoundException(fileName); } if (isReturn == null) jf.close(); else { // Return a special InputStream that makes sure that the // entry and the JarFile that it stems from are both closed // isReturn[0] = new FilterInputStream(jf.getInputStream(entry)) { @Override public void close() throws IOException { try { super.close(); } catch (IOException e) { } jf.close(); } }; } } return fileName; } @Override protected boolean innerExists(String fileName, IProgressMonitor monitor) throws CoreException { try { getResolvedFile(fileName, null); return true; } catch (FileNotFoundException e) { return false; } catch (IOException e) { throw BuckminsterException.wrap(e); } } @Override protected void innerList(List<String> files, IProgressMonitor monitor) throws CoreException { File modelRoot = getLocation(); if (modelRoot == null) return; File[] content = modelRoot.listFiles(); if (content != null) { for (File file : content) { String name = file.getName(); if (file.isDirectory()) name = name + "/"; //$NON-NLS-1$ files.add(name); } return; } if (!modelRoot.getName().endsWith(".jar")) //$NON-NLS-1$ return; ZipInputStream zi = null; try { ZipEntry ze; zi = new ZipInputStream(new BufferedInputStream(new FileInputStream(modelRoot))); while ((ze = zi.getNextEntry()) != null) { String name = ze.getName(); if (name.endsWith("/")) //$NON-NLS-1$ name = name.substring(name.length() - 1); if (name.indexOf('/', 1) < 0) { if (ze.isDirectory()) name = name + "/"; //$NON-NLS-1$ files.add(name); } } } catch (IOException e) { } finally { IOUtils.close(zi); } } @Override protected <T> T innerReadFile(String fileName, IStreamConsumer<T> consumer, IProgressMonitor monitor) throws CoreException, IOException { InputStream input = null; try { InputStream[] isHolder = new InputStream[1]; String systemId = getResolvedFile(fileName, isHolder); input = new BufferedInputStream(isHolder[0]); return consumer.consumeStream(this, systemId, input, monitor); } finally { IOUtils.close(input); } } private BundleInfo getBestBundle() { return PDETargetPlatform.getBestPlugin(componentName, getDesiredVersion(), null); } private IFeatureModel getBestFeature() { return PDETargetPlatform.getBestFeature(componentName, getDesiredVersion(), null); } private IPluginModelBase getBestPlugin() { return EclipsePlatformReaderType.getBestPlugin(componentName, getDesiredVersion(), null); } private VersionRange getDesiredVersion() { VersionRange desiredVersion = null; ProviderMatch vsMatch = getProviderMatch(); if (vsMatch != null) { Version version = vsMatch.getVersionMatch().getVersion(); if (version != null) desiredVersion = VersionHelper.exactRange(version); } return desiredVersion; } }