/*****************************************************************************
* 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.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.StringTokenizer;
import org.eclipse.buckminster.core.cspec.builder.ActionBuilder;
import org.eclipse.buckminster.core.cspec.builder.ArtifactBuilder;
import org.eclipse.buckminster.core.cspec.builder.CSpecBuilder;
import org.eclipse.buckminster.core.cspec.builder.ComponentRequestBuilder;
import org.eclipse.buckminster.core.cspec.builder.GroupBuilder;
import org.eclipse.buckminster.core.cspec.model.ComponentName;
import org.eclipse.buckminster.core.cspec.model.UpToDatePolicy;
import org.eclipse.buckminster.core.ctype.IComponentType;
import org.eclipse.buckminster.core.query.model.ComponentQuery;
import org.eclipse.buckminster.core.reader.ICatalogReader;
import org.eclipse.buckminster.core.resolver.NodeQuery;
import org.eclipse.buckminster.pde.cspecgen.CSpecGenerator;
import org.eclipse.buckminster.pde.internal.model.ExternalBundleModel;
import org.eclipse.buckminster.runtime.IOUtils;
import org.eclipse.buckminster.runtime.MonitorUtils;
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.pde.core.plugin.IFragmentModel;
import org.eclipse.pde.core.plugin.IPluginBase;
import org.eclipse.pde.core.plugin.IPluginModelBase;
import org.eclipse.pde.internal.core.ICoreConstants;
import org.eclipse.pde.internal.core.bundle.BundlePluginBase;
import org.eclipse.pde.internal.core.ibundle.IBundle;
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 CSpecFromBinary extends CSpecGenerator {
private static final String SYSTEM_BUNDLE = "org.eclipse.osgi"; //$NON-NLS-1$
private static final ComponentName SYSTEM_BUNDLE_CNAME = new ComponentName(SYSTEM_BUNDLE, IComponentType.OSGI_BUNDLE);
private final IPluginBase plugin;
public CSpecFromBinary(CSpecBuilder cspecBuilder, ICatalogReader reader, IPluginBase plugin) {
super(cspecBuilder, reader);
this.plugin = plugin;
}
/**
* Creates the attributes needed for a prebuilt bundle. The target bundle
* can be represented as a folder or a jar file.
*
* @param monitor
* @throws CoreException
*/
@Override
public void generate(IProgressMonitor monitor) throws CoreException {
monitor.beginTask(null, 20);
CSpecBuilder cspec = getCSpec();
GroupBuilder classpath = cspec.addGroup(ATTRIBUTE_JAVA_BINARIES, true);
GroupBuilder bundleJars = cspec.addGroup(ATTRIBUTE_BUNDLE_JARS, true);
GroupBuilder bundleAndFragments = cspec.addGroup(ATTRIBUTE_BUNDLE_AND_FRAGMENTS, true);
bundleJars.addLocalPrerequisite(bundleAndFragments);
// We need an empty group for binary bundles
cspec.addGroup(ATTRIBUTE_BUNDLE_AND_FRAGMENTS_SOURCE, true);
cspec.addGroup(ATTRIBUTE_PRODUCT_CONFIG_EXPORTS, true);
IPluginModelBase model = plugin.getPluginModel();
if (model instanceof IFragmentModel)
addBundleHostDependency((IFragmentModel) model);
else {
ActionBuilder copyTargetFragments = cspec.addAction(ATTRIBUTE_TARGET_FRAGMENTS, false, ACTOR_COPY_TARGET_FRAGMENTS, false);
copyTargetFragments.setProductAlias(ALIAS_OUTPUT);
copyTargetFragments.setProductBase(OUTPUT_DIR_FRAGMENTS);
copyTargetFragments.setUpToDatePolicy(UpToDatePolicy.ACTOR);
bundleAndFragments.addLocalPrerequisite(copyTargetFragments);
}
// There are two types of binaries. The one that contain jar files (and
// must be unpacked
// in order to function) and the one that is a jar file in itself.
//
addImports();
MonitorUtils.worked(monitor, 10);
IPath parentDir = new Path(".."); //$NON-NLS-1$
String location = model.getInstallLocation();
File locationFile = (location != null) ? new File(location) : null;
boolean isFile = (locationFile != null) && locationFile.isFile();
cspec.setShortDesc(expand(plugin.getName()));
if (isFile) {
// No unpacked bundle exists (or should ever exist). We're happy
// with what we have.
//
cspec.addGroup(ATTRIBUTE_FULL_CLEAN, true);
ArtifactBuilder pluginExport = cspec.addArtifact(ATTRIBUTE_BUNDLE_JAR, true, null);
pluginExport.addPath(Path.fromOSString(locationFile.getName()));
pluginExport.setBase(parentDir); // we want the site/plugins folder,
// i.e. the parent of the jar
classpath.addLocalPrerequisite(pluginExport);
bundleAndFragments.addLocalPrerequisite(pluginExport);
} else {
// This bundle is a folder. Gather artifacts to be included in the
// classpath
//
IBundle bundle = null;
if (plugin instanceof BundlePluginBase)
bundle = ((BundlePluginBase) plugin).getBundle();
else {
if (locationFile != null && locationFile.isDirectory()) {
InputStream input = null;
try {
input = new BufferedInputStream(new FileInputStream(new File(locationFile, BUNDLE_FILE)));
ExternalBundleModel ebm = new ExternalBundleModel(locationFile);
ebm.load(input, false);
bundle = ebm.getBundle();
} catch (IOException e) {
} finally {
IOUtils.close(input);
}
}
}
String bundleClassPath = null;
if (bundle != null) {
bundleClassPath = bundle.getHeader(Constants.BUNDLE_CLASSPATH);
setFilter(bundle.getHeader(ICoreConstants.PLATFORM_FILTER));
}
String jarName = buildArtifactName(plugin.getId(), plugin.getVersion(), true);
boolean isImportedBundle = false;
ArtifactBuilder bundleClasspath = null;
if (bundleClassPath == null)
classpath.addSelfRequirement();
else {
// Create an artifact that contains all entries listed in the
// classpath
//
bundleClasspath = cspec.addArtifact(ATTRIBUTE_BUNDLE_CLASSPATH, false, null);
StringTokenizer tokens = new StringTokenizer(bundleClassPath, ","); //$NON-NLS-1$
while (tokens.hasMoreTokens()) {
String token = tokens.nextToken().trim();
if (token.equals(jarName))
isImportedBundle = true;
bundleClasspath.addPath(new Path(token));
}
classpath.addLocalPrerequisite(bundleClasspath);
}
ActionBuilder bundleExport;
if (!isImportedBundle) {
// In order to create a jar of the unpackedPlugin, we need a
// temporary directory
// since this artifact is not a workspace artifact
//
bundleExport = addAntAction(ATTRIBUTE_BUNDLE_JAR, TASK_RECREATE_JAR, true);
bundleExport.addProductPath(Path.fromPortableString(jarName));
bundleExport.getPrerequisitesBuilder().addSelfRequirement();
} else {
bundleExport = addAntAction(ATTRIBUTE_BUNDLE_JAR, TASK_COPY_GROUP, true);
if (bundleClasspath.getPaths().size() == 1)
bundleExport.getPrerequisitesBuilder().addLocalPrerequisite(bundleClasspath);
else {
ArtifactBuilder importedJar = cspec.addArtifact(ATTRIBUTE_IMPORTED_JAR, false, null);
importedJar.addPath(Path.fromPortableString(jarName));
bundleExport.getPrerequisitesBuilder().addLocalPrerequisite(importedJar);
}
}
bundleExport.setProductAlias(ALIAS_OUTPUT);
bundleExport.setProductBase(OUTPUT_DIR);
bundleExport.setPrerequisitesAlias(ALIAS_REQUIREMENTS);
bundleAndFragments.addLocalPrerequisite(bundleExport);
generateRemoveDirAction("build", OUTPUT_DIR, true, ATTRIBUTE_FULL_CLEAN); //$NON-NLS-1$
}
monitor.done();
}
@Override
protected String getProductOutputFolder(String productId) {
return null;
}
@Override
protected String getPropertyFileName() {
return PLUGIN_PROPERTIES_FILE;
}
private void addImports() throws CoreException {
IPluginModelBase model = plugin.getPluginModel();
boolean isFragment = model.isFragmentModel();
NodeQuery query = getReader().getNodeQuery();
ComponentQuery cquery = query.getComponentQuery();
CSpecBuilder cspec = getCSpec();
GroupBuilder reExports = cspec.getRequiredGroup(ATTRIBUTE_JAVA_BINARIES);
GroupBuilder bundleJars = cspec.getRequiredGroup(ATTRIBUTE_BUNDLE_JARS);
ImportSpecification[] imports = getImports(plugin);
if (imports.length == 0) {
// Just add the mandatory system bundle. It's needed since
// that bundle defines the execution environments.
//
if (!(isFragment || SYSTEM_BUNDLE.equals(cspec.getName()) || cquery.skipComponent(SYSTEM_BUNDLE_CNAME, query.getContext())))
cspec.addDependency(createDependency(SYSTEM_BUNDLE, IComponentType.OSGI_BUNDLE, (String) null, null));
return;
}
for (ImportSpecification pluginImport : imports) {
if (pluginImport.isOptional())
//
// We don't care about expressing dependencies to
// optional plugins when we peruse the runtime
// environment.
//
continue;
String pluginId = pluginImport.getName();
if (pluginId.equals(Constants.SYSTEM_BUNDLE_SYMBOLICNAME))
continue;
ComponentRequestBuilder dependency = createDependency(pluginImport, IComponentType.OSGI_BUNDLE);
if (skipComponent(cquery, dependency) || !addDependency(dependency))
continue;
addExternalPrerequisite(bundleJars, dependency, ATTRIBUTE_BUNDLE_JARS);
if (pluginImport.isExported())
addExternalPrerequisite(reExports, dependency, ATTRIBUTE_JAVA_BINARIES);
}
}
}