/*****************************************************************************
* 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.pde.cspecgen.bundle;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import org.eclipse.buckminster.core.TargetPlatform;
import org.eclipse.buckminster.core.cspec.builder.CSpecBuilder;
import org.eclipse.buckminster.core.ctype.IComponentType;
import org.eclipse.buckminster.core.ctype.MissingCSpecSourceException;
import org.eclipse.buckminster.core.helpers.AccessibleByteArrayOutputStream;
import org.eclipse.buckminster.core.metadata.MissingComponentException;
import org.eclipse.buckminster.core.metadata.model.Resolution;
import org.eclipse.buckminster.core.reader.ICatalogReader;
import org.eclipse.buckminster.core.reader.IComponentReader;
import org.eclipse.buckminster.core.reader.IStreamConsumer;
import org.eclipse.buckminster.core.reader.URLCatalogReaderType;
import org.eclipse.buckminster.core.reader.URLFileReader;
import org.eclipse.buckminster.core.reader.ZipArchiveReader;
import org.eclipse.buckminster.core.version.ProviderMatch;
import org.eclipse.buckminster.core.version.VersionHelper;
import org.eclipse.buckminster.pde.IPDEConstants;
import org.eclipse.buckminster.pde.Messages;
import org.eclipse.buckminster.pde.PDEPlugin;
import org.eclipse.buckminster.pde.cspecgen.CSpecGenerator;
import org.eclipse.buckminster.pde.cspecgen.PDEBuilder;
import org.eclipse.buckminster.pde.internal.EclipseImportReader;
import org.eclipse.buckminster.pde.internal.EclipsePlatformReader;
import org.eclipse.buckminster.pde.internal.model.ExternalBuildModel;
import org.eclipse.buckminster.pde.internal.model.ExternalBundleModel;
import org.eclipse.buckminster.pde.internal.model.ExternalExtensionsModel;
import org.eclipse.buckminster.runtime.BuckminsterException;
import org.eclipse.buckminster.runtime.MonitorUtils;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.equinox.internal.p2.metadata.OSGiVersion;
import org.eclipse.equinox.p2.metadata.Version;
import org.eclipse.osgi.util.NLS;
import org.eclipse.pde.core.IModel;
import org.eclipse.pde.core.build.IBuildModel;
import org.eclipse.pde.core.plugin.IPluginBase;
import org.eclipse.pde.core.plugin.IPluginModelBase;
import org.eclipse.pde.core.plugin.PluginRegistry;
import org.eclipse.pde.internal.build.IBuildPropertiesConstants;
import org.eclipse.pde.internal.core.bundle.BundleFragmentModel;
import org.eclipse.pde.internal.core.bundle.BundleModel;
import org.eclipse.pde.internal.core.bundle.BundlePluginModel;
import org.eclipse.pde.internal.core.bundle.BundlePluginModelBase;
import org.eclipse.pde.internal.core.ibundle.IBundle;
import org.eclipse.pde.internal.core.plugin.ExternalFragmentModel;
import org.eclipse.pde.internal.core.plugin.ExternalPluginModel;
import org.osgi.framework.Constants;
/**
* A CSpec builder that creates a cspec using the META-INF/MANIFEST.MF,
* plugin.xml and fragment.xml files.
*
* @author Thomas Hallgren
*/
@SuppressWarnings("restriction")
public class BundleBuilder extends PDEBuilder implements IBuildPropertiesConstants {
private static IPath platformPluginsFolder = Path.fromOSString(TargetPlatform.getPlatformInstallLocation().getAbsolutePath()).append(
IPDEConstants.PLUGINS_FOLDER);
private static void loadModel(ICatalogReader reader, String file, final IModel model, IProgressMonitor monitor) throws CoreException,
FileNotFoundException {
try {
reader.readFile(file, new IStreamConsumer<Object>() {
@Override
public Object consumeStream(IComponentReader fileReader, String streamName, InputStream stream, IProgressMonitor mon)
throws CoreException {
int len;
byte[] buf = new byte[4096];
@SuppressWarnings("resource")
AccessibleByteArrayOutputStream bld = new AccessibleByteArrayOutputStream();
try {
while ((len = stream.read(buf)) > 0) {
for (int idx = 0; idx < len; ++idx) {
byte b = buf[idx];
if (b != '\r')
bld.write(b);
}
}
} catch (IOException e) {
throw BuckminsterException.wrap(e);
}
model.load(bld.getInputStream(), true);
return null;
}
}, monitor);
} catch (FileNotFoundException e) {
throw e;
} catch (IOException e) {
throw BuckminsterException.wrap(e);
}
}
private static IPluginModelBase parsePluginModelBase(ICatalogReader reader, boolean forResolutionAidOnly, IBuildModel[] buildModelHandle,
IProgressMonitor monitor) throws CoreException {
File locationFile = null;
if (reader instanceof EclipsePlatformReader) {
MonitorUtils.complete(monitor);
try {
IPluginModelBase pluginModelBase = ((EclipsePlatformReader) reader).getPluginModelBase();
if (forResolutionAidOnly)
return pluginModelBase;
String location = pluginModelBase.getInstallLocation();
if (location == null)
throw new MissingCSpecSourceException(reader.getProviderMatch());
if (platformPluginsFolder.isPrefixOf(Path.fromOSString(location)))
return pluginModelBase;
locationFile = new File(location);
if (locationFile.isFile())
return pluginModelBase;
// Self hosted from workspace. We can (and must) build this one
// from
// source
//
reader = (ICatalogReader) URLCatalogReaderType.getReader(locationFile.toURI().toURL(), null);
} catch (MissingComponentException e) {
} catch (IllegalStateException e) {
throw new MissingCSpecSourceException(reader.getProviderMatch());
} catch (MalformedURLException e) {
throw BuckminsterException.wrap(e);
}
}
monitor.beginTask(null, 7000);
try {
// This is an OSGi style plugin. Most of the dependencies and
// other
// info that we're interested in is stored in the
// META-INF/MANIFEST.MF
// file.
//
try {
if (locationFile == null) {
if (reader instanceof ZipArchiveReader) {
IComponentReader fr = ((ZipArchiveReader) reader).getFileReader();
if (fr instanceof URLFileReader) {
URI uri = ((URLFileReader) fr).getURI();
try {
URL url = FileLocator.resolve(uri.toURL());
if ("file".equalsIgnoreCase(url.getProtocol())) //$NON-NLS-1$
locationFile = new File(url.toURI());
} catch (IOException e) {
} catch (URISyntaxException e) {
}
}
}
}
boolean fragment = false;
BundleModel model = new ExternalBundleModel(locationFile);
loadModel(reader, BUNDLE_FILE, model, MonitorUtils.subMonitor(monitor, 1000));
IBundle bundle = model.getBundle();
if (bundle.getHeader(Constants.BUNDLE_SYMBOLICNAME) == null) {
ProviderMatch pm = reader.getProviderMatch();
String cName = pm.getComponentName();
if (!cName.endsWith(".source")) { //$NON-NLS-1$
String bundleManifestVersion = bundle.getHeader(Constants.BUNDLE_MANIFESTVERSION);
if (bundleManifestVersion == null)
throw new FileNotFoundException(Messages.not_an_OSGi_manifest);
PDEPlugin.getLogger().warning(
NLS.bind(Messages.No_bundle_id_found_in_0, new File(reader.getLocation(), BUNDLE_FILE).getAbsolutePath()));
bundle.setHeader(Constants.BUNDLE_SYMBOLICNAME, "<undefined bundle id>"); //$NON-NLS-1$
} else
bundle.setHeader(Constants.BUNDLE_SYMBOLICNAME, cName);
Version v = pm.getVersionMatch().getVersion();
String vstr;
if (v == null)
vstr = null;
else if (v instanceof OSGiVersion)
vstr = v.toString();
else
vstr = v.getOriginal();
if (vstr != null)
bundle.setHeader(Constants.BUNDLE_VERSION, vstr);
}
fragment = model.isFragmentModel();
BundlePluginModelBase bmodel = fragment ? new BundleFragmentModel() : new BundlePluginModel();
bmodel.setBundleModel(model);
bmodel.setEnabled(true);
if (forResolutionAidOnly)
return bmodel;
// Extensions etc. that are not part of the OSGi can still be
// found in the plugin.xml or fragment.xml
//
try {
String extensionsFile = fragment ? FRAGMENT_FILE : PLUGIN_FILE;
ExternalExtensionsModel extModel = new ExternalExtensionsModel();
loadModel(reader, extensionsFile, extModel, MonitorUtils.subMonitor(monitor, 1000));
bmodel.setExtensionsModel(extModel);
} catch (FileNotFoundException e) {
}
try {
IBuildModel buildModel = new ExternalBuildModel();
loadModel(reader, BUILD_PROPERTIES_FILE, buildModel, MonitorUtils.subMonitor(monitor, 1000));
buildModelHandle[0] = buildModel;
} catch (FileNotFoundException e) {
}
return bmodel;
} catch (FileNotFoundException e) {
}
try {
ExternalPluginModel pm = new ExternalPluginModel();
loadModel(reader, PLUGIN_FILE, pm, MonitorUtils.subMonitor(monitor, 1000));
return pm;
} catch (FileNotFoundException e1) {
}
try {
ExternalFragmentModel pm = new ExternalFragmentModel();
loadModel(reader, FRAGMENT_FILE, pm, MonitorUtils.subMonitor(monitor, 1000));
return pm;
} catch (FileNotFoundException e1) {
throw new MissingCSpecSourceException(reader.getProviderMatch());
}
} finally {
monitor.done();
}
}
@Override
public String getComponentTypeID() {
return IComponentType.OSGI_BUNDLE;
}
@Override
protected Resolution createResolution(IComponentReader reader, CSpecBuilder cspecBuilder) throws CoreException {
if (reader instanceof EclipseImportReader) {
EclipseImportReader eclipseImportReader = (EclipseImportReader) reader;
return super.createResolution(reader, cspecBuilder, eclipseImportReader.isUnpack());
}
return super.createResolution(reader, cspecBuilder);
}
@Override
protected void parseFile(CSpecBuilder cspecBuilder, boolean forResolutionAidOnly, ICatalogReader reader, IProgressMonitor monitor)
throws CoreException {
monitor.beginTask(null, 100);
try {
IBuildModel[] buildModelHandle = new IBuildModel[1];
IPluginBase pluginBase = parsePluginModelBase(reader, forResolutionAidOnly, buildModelHandle, MonitorUtils.subMonitor(monitor, 50))
.getPluginBase();
cspecBuilder.setName(pluginBase.getId());
cspecBuilder.setComponentTypeID(getComponentTypeID());
cspecBuilder.setVersion(VersionHelper.parseVersion(pluginBase.getVersion()));
if (forResolutionAidOnly)
return;
IPluginModelBase model = pluginBase.getPluginModel();
setModel(model);
IBuildModel buildModel = buildModelHandle[0];
if (buildModel == null && model.getUnderlyingResource() != null)
buildModel = PluginRegistry.createBuildModel(model);
boolean fromProject = (buildModel != null);
CSpecGenerator generator;
if (fromProject)
generator = new CSpecFromSource(cspecBuilder, reader, pluginBase, buildModel);
else
generator = new CSpecFromBinary(cspecBuilder, reader, pluginBase);
generator.generate(monitor);
} finally {
monitor.done();
}
}
}