| package org.eclipse.tycho.core.osgitools; |
| |
| import static org.osgi.framework.Constants.BUNDLE_CLASSPATH; |
| import static org.osgi.framework.Constants.BUNDLE_VERSION; |
| |
| import java.io.InputStream; |
| |
| import org.eclipse.osgi.framework.util.Headers; |
| import org.eclipse.osgi.internal.resolver.StateObjectFactoryImpl; |
| import org.eclipse.osgi.service.resolver.BundleDescription; |
| import org.eclipse.osgi.util.ManifestElement; |
| import org.eclipse.tycho.ArtifactKey; |
| import org.eclipse.tycho.ArtifactType; |
| import org.eclipse.tycho.DefaultArtifactKey; |
| import org.eclipse.tycho.core.ee.ExecutionEnvironmentUtils; |
| import org.eclipse.tycho.core.ee.StandardExecutionEnvironment; |
| import org.eclipse.tycho.core.ee.UnknownEnvironmentException; |
| import org.osgi.framework.BundleException; |
| import org.osgi.framework.Constants; |
| import org.osgi.framework.Version; |
| |
| /** |
| * Convenience wrapper around {@link Headers} and {@link ManifestElement} which adds typed getters |
| * and value caching for commonly used headers. This is a read-only API. |
| * |
| */ |
| public class OsgiManifest { |
| |
| private static final StandardExecutionEnvironment[] EMPTY_EXEC_ENV = new StandardExecutionEnvironment[0]; |
| |
| private String location; |
| private Headers<String, String> headers; |
| |
| // cache for parsed values of commonly used headers |
| private String bundleSymbolicName; |
| private String bundleVersion; |
| private String[] bundleClassPath; |
| private StandardExecutionEnvironment[] executionEnvironments; |
| private boolean isDirectoryShape; |
| |
| private OsgiManifest(InputStream stream, String location) throws OsgiManifestParserException { |
| this.location = location; |
| try { |
| this.headers = Headers.parseManifest(stream); |
| // this will do more strict validation of headers on OSGi semantical level |
| BundleDescription bundleDescription = StateObjectFactoryImpl.defaultFactory.createBundleDescription(null, |
| headers, location, 0L); |
| this.bundleSymbolicName = bundleDescription.getSymbolicName(); |
| } catch (BundleException e) { |
| throw new OsgiManifestParserException(location, e); |
| } |
| this.bundleVersion = parseBundleVersion(); |
| this.bundleClassPath = parseBundleClasspath(); |
| this.isDirectoryShape = parseDirectoryShape(); |
| this.executionEnvironments = parseExecutionEnvironments(); |
| } |
| |
| private StandardExecutionEnvironment[] parseExecutionEnvironments() { |
| ManifestElement[] brees = getManifestElements(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT); |
| if (brees == null || brees.length == 0) { |
| return EMPTY_EXEC_ENV; |
| } |
| StandardExecutionEnvironment[] envs = new StandardExecutionEnvironment[brees.length]; |
| try { |
| for (int i = 0; i < brees.length; i++) { |
| envs[i] = ExecutionEnvironmentUtils.getExecutionEnvironment(brees[i].getValue()); |
| } |
| } catch (UnknownEnvironmentException e) { |
| throw new OsgiManifestParserException(location, e); |
| } |
| return envs; |
| } |
| |
| private String parseBundleVersion() { |
| String versionString = parseMandatoryFirstValue(BUNDLE_VERSION); |
| try { |
| return Version.parseVersion(versionString).toString(); |
| } catch (NumberFormatException e) { |
| throw new InvalidOSGiManifestException(location, "Bundle-Version '" + versionString + "' is invalid"); |
| } catch (IllegalArgumentException e) { |
| throw new InvalidOSGiManifestException(location, e); |
| } |
| } |
| |
| private String parseMandatoryFirstValue(String headerKey) throws InvalidOSGiManifestException { |
| String value = headers.get(headerKey); |
| if (value == null) { |
| throw new InvalidOSGiManifestException(location, "MANIFEST header '" + headerKey + "' not found"); |
| } |
| ManifestElement[] elements = null; |
| try { |
| elements = ManifestElement.parseHeader(headerKey, value); |
| } catch (BundleException e) { |
| throw new InvalidOSGiManifestException(location, e); |
| } |
| if (elements == null || elements.length == 0) { |
| throw new InvalidOSGiManifestException(location, "value for MANIFEST header '" + headerKey + "' is empty"); |
| } |
| return elements[0].getValue(); |
| } |
| |
| private boolean parseDirectoryShape() { |
| ManifestElement[] bundleShapeElements = parseHeader("Eclipse-BundleShape"); |
| return bundleShapeElements != null && bundleShapeElements.length > 0 |
| && "dir".equals(bundleShapeElements[0].getValue()); |
| } |
| |
| public Headers<String, String> getHeaders() { |
| return headers; |
| } |
| |
| public String getValue(String key) { |
| return headers.get(key); |
| } |
| |
| public String getBundleSymbolicName() { |
| return bundleSymbolicName; |
| } |
| |
| public String getBundleVersion() { |
| return bundleVersion; |
| } |
| |
| /** |
| * Returns the bundle's key in the Eclipse artifact coordinate system. |
| */ |
| public ArtifactKey toArtifactKey() { |
| return new DefaultArtifactKey(ArtifactType.TYPE_ECLIPSE_PLUGIN, getBundleSymbolicName(), getBundleVersion()); |
| } |
| |
| public String[] getBundleClasspath() { |
| return bundleClassPath; |
| } |
| |
| public StandardExecutionEnvironment[] getExecutionEnvironments() { |
| return executionEnvironments; |
| } |
| |
| /** |
| * Returns true if Eclipse-BundleShape header is set to dir. |
| * |
| * http://help.eclipse.org/galileo/index.jsp?topic=/org.eclipse.platform.doc.isv/reference/misc/ |
| * bundle_manifest.html |
| * |
| * http://eclipsesource.com/blogs/2009/01/20/tip-eclipse-bundleshape/ |
| */ |
| public boolean isDirectoryShape() { |
| return isDirectoryShape; |
| } |
| |
| static OsgiManifest parse(InputStream stream, String location) throws OsgiManifestParserException { |
| return new OsgiManifest(stream, location); |
| } |
| |
| private ManifestElement[] parseHeader(String key) { |
| String value = headers.get(key); |
| if (value == null) { |
| return null; |
| } |
| try { |
| return ManifestElement.parseHeader(key, value); |
| } catch (BundleException e) { |
| throw new OsgiManifestParserException(location, e); |
| } |
| } |
| |
| public ManifestElement[] getManifestElements(String key) throws OsgiManifestParserException { |
| try { |
| return ManifestElement.parseHeader(key, headers.get(key)); |
| } catch (BundleException e) { |
| throw new OsgiManifestParserException(location, e); |
| } |
| } |
| |
| private String[] parseBundleClasspath() { |
| String[] result = new String[] { "." }; |
| String classPathValue = getValue(BUNDLE_CLASSPATH); |
| if (classPathValue != null) { |
| ManifestElement[] classpathEntries = getManifestElements(BUNDLE_CLASSPATH); |
| if (classpathEntries != null) { |
| result = new String[classpathEntries.length]; |
| for (int i = 0; i < classpathEntries.length; i++) { |
| result[i] = classpathEntries[i].getValue(); |
| } |
| } |
| } |
| return result; |
| } |
| |
| } |