blob: 284e1e4d0b153a4bd322cd9e81c1ff145b711f2e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2010 VMware Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* VMware Inc. - initial contribution
*******************************************************************************/
package org.eclipse.virgo.kernel.artifact.library;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.Map.Entry;
import org.eclipse.virgo.kernel.artifact.library.internal.ArtifactDescriptorLibraryDefinition;
import org.eclipse.virgo.repository.ArtifactBridge;
import org.eclipse.virgo.repository.ArtifactDescriptor;
import org.eclipse.virgo.repository.ArtifactGenerationException;
import org.eclipse.virgo.repository.HashGenerator;
import org.eclipse.virgo.repository.builder.ArtifactDescriptorBuilder;
import org.eclipse.virgo.repository.builder.AttributeBuilder;
import org.eclipse.virgo.util.common.CaseInsensitiveMap;
import org.eclipse.virgo.util.common.StringUtils;
import org.eclipse.virgo.util.osgi.manifest.BundleManifest;
import org.eclipse.virgo.util.osgi.manifest.BundleManifestFactory;
import org.eclipse.virgo.util.osgi.manifest.ImportedBundle;
import org.eclipse.virgo.util.osgi.manifest.parse.HeaderDeclaration;
import org.eclipse.virgo.util.osgi.manifest.parse.HeaderParserFactory;
import org.eclipse.virgo.util.parser.manifest.ManifestContents;
import org.eclipse.virgo.util.parser.manifest.ManifestParser;
import org.eclipse.virgo.util.parser.manifest.RecoveringManifestParser;
import org.osgi.framework.Version;
public class LibraryBridge implements ArtifactBridge {
public static final String LIBRARY_VERSION = "Library-Version";
public static final String LIBRARY_SYMBOLICNAME = "Library-SymbolicName";
public static final String IMPORT_BUNDLE = "Import-Bundle";
public static final String LIBRARY_NAME = "Library-Name";
public static final String LIBRARY_DESCRIPTION = "Library-Description";
private static final String LIBRARY_DESCRIPTOR_SUFFIX = ".libd";
private static final String DEFAULT_LIBRARY_VERSION = "0";
public static final String RAW_HEADER_PREFIX = "RAW_HEADER:";
private static final String VERSION_ATTRIBUTE = "version";
private static final String RESOLUTION_DIRECTIVE = "resolution";
private static final String IMPORT_SCOPE_DIRECTIVE = "import-scope";
private final HashGenerator hashGenerator;
public LibraryBridge(HashGenerator hashGenerator) {
this.hashGenerator = hashGenerator;
}
public ArtifactDescriptor generateArtifactDescriptor(File artifactFile) throws ArtifactGenerationException {
if (!artifactFile.getName().endsWith(LIBRARY_DESCRIPTOR_SUFFIX)) {
return null;
}
ManifestContents manifestContents;
try {
manifestContents = getManifestContents(artifactFile);
} catch (IOException ie) {
throw new ArtifactGenerationException("Unable to read library definition", LibraryDefinition.LIBRARY_TYPE, ie);
}
CaseInsensitiveMap<String> contentsMap = new CaseInsensitiveMap<String>();
contentsMap.putAll(manifestContents.getMainAttributes());
ArtifactDescriptorBuilder builder = new ArtifactDescriptorBuilder();
builder.setUri(artifactFile.toURI());
builder.setType(LibraryDefinition.LIBRARY_TYPE);
String name = createAttributeFromLibrarySymbolicName(contentsMap, artifactFile, builder);
builder.setName(name);
Version version = createAttributeFromLibraryVersion(contentsMap, builder);
builder.setVersion(version);
createAttributesFromImportBundle(contentsMap, artifactFile, builder);
createAttributeFromLibraryName(contentsMap, builder);
createAttributeFromLibraryDescription(contentsMap, builder);
createAttributesFromRawHeaders(contentsMap, builder);
this.hashGenerator.generateHash(builder, artifactFile);
return builder.build();
}
private static ManifestContents getManifestContents(File file) throws IOException {
ManifestParser manifestParser = new RecoveringManifestParser();
try (Reader reader = new InputStreamReader(new FileInputStream(file), UTF_8)) {
return manifestParser.parse(reader);
}
}
private static String createAttributeFromLibrarySymbolicName(CaseInsensitiveMap<String> manifestAttributes, File artifact,
ArtifactDescriptorBuilder builder) throws ArtifactGenerationException {
String symbolicNameString = getRequiredHeader(LIBRARY_SYMBOLICNAME, manifestAttributes, artifact);
HeaderDeclaration symbolicNameDeclaration = HeaderParserFactory.newHeaderParser(null).parseLibrarySymbolicName(symbolicNameString);
String symbolicName = symbolicNameDeclaration.getNames().get(0);
AttributeBuilder attBuilder = new AttributeBuilder();
attBuilder.setName(LIBRARY_SYMBOLICNAME);
attBuilder.setValue(symbolicName);
builder.addAttribute(attBuilder.build());
return symbolicName;
}
private static Version createAttributeFromLibraryVersion(CaseInsensitiveMap<String> manifestAttributes, ArtifactDescriptorBuilder builder) {
String versionString = manifestAttributes.get(LIBRARY_VERSION);
if (!StringUtils.hasText(versionString)) {
versionString = DEFAULT_LIBRARY_VERSION;
}
Version version = new Version(versionString);
builder.addAttribute(new AttributeBuilder().setName(LIBRARY_VERSION).setValue(version.toString()).build());
return version;
}
private static void createAttributesFromImportBundle(CaseInsensitiveMap<String> manifestAttributes, File artifact,
ArtifactDescriptorBuilder builder) throws ArtifactGenerationException {
String importBundleString = getRequiredHeader(IMPORT_BUNDLE, manifestAttributes, artifact);
Dictionary<String, String> headers = new Hashtable<String, String>();
headers.put(IMPORT_BUNDLE, importBundleString);
BundleManifest manifest = BundleManifestFactory.createBundleManifest(headers);
List<ImportedBundle> importedBundles = manifest.getImportBundle().getImportedBundles();
for (ImportedBundle importedBundle : importedBundles) {
AttributeBuilder attBuilder = new AttributeBuilder();
attBuilder.setName(IMPORT_BUNDLE);
attBuilder.setValue(importedBundle.getBundleSymbolicName());
attBuilder.putProperties(RESOLUTION_DIRECTIVE, importedBundle.getResolution().toString().toLowerCase(Locale.ENGLISH));
attBuilder.putProperties(VERSION_ATTRIBUTE, importedBundle.getVersion().toParseString());
if (importedBundle.isApplicationImportScope()) {
attBuilder.putProperties(IMPORT_SCOPE_DIRECTIVE, "application");
}
builder.addAttribute(attBuilder.build());
}
}
private static void createAttributeFromLibraryName(CaseInsensitiveMap<String> manifestAttributes, ArtifactDescriptorBuilder builder) {
String name = manifestAttributes.get(LIBRARY_NAME);
if (name != null) {
builder.addAttribute(new AttributeBuilder().setName(LIBRARY_NAME).setValue(name).build());
}
}
private static void createAttributeFromLibraryDescription(CaseInsensitiveMap<String> manifestAttributes, ArtifactDescriptorBuilder builder) {
String name = manifestAttributes.get(LIBRARY_DESCRIPTION);
if (name != null) {
builder.addAttribute(new AttributeBuilder().setName(LIBRARY_DESCRIPTION).setValue(name).build());
}
}
private static void createAttributesFromRawHeaders(CaseInsensitiveMap<String> manifestAttributes, ArtifactDescriptorBuilder builder) {
for (Entry<String, String> entry : manifestAttributes.entrySet()) {
builder.addAttribute(new AttributeBuilder().setName(RAW_HEADER_PREFIX + entry.getKey()).setValue(entry.getValue()).build());
}
}
private static String getRequiredHeader(String name, CaseInsensitiveMap<String> attrs, File artifactFile) throws ArtifactGenerationException {
String value = attrs.get(name);
if (value == null || value.trim().length() == 0) {
throw new ArtifactGenerationException(String.format("Required attribute '%s' is missing from library descriptor '%s'.", name,
artifactFile.getName()), LibraryDefinition.LIBRARY_TYPE);
}
return value;
}
public static List<ImportedBundle> parseImportBundle(String importBundleString) {
Dictionary<String, String> headers = new Hashtable<String, String>();
headers.put(IMPORT_BUNDLE, importBundleString);
BundleManifest manifest = BundleManifestFactory.createBundleManifest(headers);
return manifest.getImportBundle().getImportedBundles();
}
public static LibraryDefinition createLibraryDefinition(ArtifactDescriptor artefact) {
return new ArtifactDescriptorLibraryDefinition(artefact);
}
}