Permalink
Browse files

Support for plain JARs (identity and content only)

  • Loading branch information...
1 parent 2209c18 commit e3f34f646a26359055fed70976d8071244a80683 @njbartlett njbartlett committed Mar 20, 2013
@@ -27,6 +27,7 @@
// Resource types
public static final String RESOURCE_TYPE_BUNDLE = "osgi.bundle";
public static final String RESOURCE_TYPE_FRAGMENT = "osgi.fragment";
+ public static final String RESOURCE_TYPE_PLAIN_JAR = "jarfile";
// Content attributes
public static final String ATTR_CONTENT_URL = "url";
@@ -1 +1 @@
-version 1.0.1
+version 1.0.2
@@ -39,7 +39,7 @@ Private-Package:\
${osgi-pkgs}
# Main headers
-Bundle-Version: 0.0.3.${tstamp}
+Bundle-Version: 0.0.4.${tstamp}
Bundle-Name: BIndex2: Repository Index Generator (Standalone)
Main-Class: org.osgi.impl.bundle.bindex.cli.Index
Bundle-Activator: org.osgi.service.indexer.osgi.Activator
@@ -30,4 +30,4 @@ Export-Package:\
org.osgi.service.indexer,\
org.osgi.service.log
-Bundle-Version: 0.0.3.${tstamp}
+Bundle-Version: 0.0.4.${tstamp}
@@ -39,8 +39,8 @@
private static final String PROVIDE_CAPABILITY = "Provide-Capability";
private static final String REQUIRE_CAPABILITY = "Require-Capability";
- // The mime-type of an OSGi bundle
- private static final String MIME_TYPE_OSGI_BUNDLE = "application/vnd.osgi.bundle";
+ // Filename suffix for JAR files
+ private static final String SUFFIX_JAR = ".jar";
private final ThreadLocal<GeneratorState> state = new ThreadLocal<GeneratorState>();
@SuppressWarnings("unused")
@@ -51,29 +51,44 @@ public BundleAnalyzer(LogService log) {
}
public void analyzeResource(Resource resource, List<Capability> capabilities, List<Requirement> requirements) throws Exception {
- doIdentity(resource, capabilities);
- doContent(resource, capabilities);
- doBundleAndHost(resource, capabilities);
- doExports(resource, capabilities);
- doImports(resource, requirements);
- doRequireBundles(resource, requirements);
- doFragment(resource, requirements);
- doExportService(resource, capabilities);
- doImportService(resource, requirements);
- doBREE(resource, requirements);
- doCapabilities(resource, capabilities);
- doRequirements(resource, requirements);
- doBundleNativeCode(resource, requirements);
+ MimeType mimeType = Util.getMimeType(resource);
+ if (mimeType == MimeType.Bundle || mimeType == MimeType.Fragment) {
+ doBundleIdentity(resource, mimeType, capabilities);
+ doContent(resource, mimeType, capabilities);
+ doBundleAndHost(resource, capabilities);
+ doExports(resource, capabilities);
+ doImports(resource, requirements);
+ doRequireBundles(resource, requirements);
+ doFragment(resource, requirements);
+ doExportService(resource, capabilities);
+ doImportService(resource, requirements);
+ doBREE(resource, requirements);
+ doCapabilities(resource, capabilities);
+ doRequirements(resource, requirements);
+ doBundleNativeCode(resource, requirements);
+ } else {
+ doPlainJarIdentity(resource, capabilities);
+ doContent(resource, mimeType, capabilities);
+ }
}
- private void doIdentity(Resource resource, List<? super Capability> caps) throws Exception {
+ private void doBundleIdentity(Resource resource, MimeType mimeType, List<? super Capability> caps) throws Exception {
Manifest manifest = resource.getManifest();
if (manifest == null)
throw new IllegalArgumentException("Missing bundle manifest.");
- Attributes attribs = manifest.getMainAttributes();
- String fragmentHost = attribs.getValue(Constants.FRAGMENT_HOST);
- String identity = (fragmentHost == null) ? Namespaces.RESOURCE_TYPE_BUNDLE : Namespaces.RESOURCE_TYPE_FRAGMENT;
+ String type;
+ switch (mimeType) {
+ case Bundle:
+ type = Namespaces.RESOURCE_TYPE_BUNDLE;
+ break;
+ case Fragment:
+ type = Namespaces.RESOURCE_TYPE_FRAGMENT;
+ break;
+ default:
+ type = Namespaces.RESOURCE_TYPE_PLAIN_JAR;
+ break;
+ }
SymbolicName bsn = Util.getSymbolicName(resource);
boolean singleton = Boolean.TRUE.toString().equalsIgnoreCase(bsn.getAttributes().get(Constants.SINGLETON_DIRECTIVE + ":"));
@@ -83,12 +98,38 @@ private void doIdentity(Resource resource, List<? super Capability> caps) throws
Builder builder = new Builder()
.setNamespace(Namespaces.NS_IDENTITY)
.addAttribute(Namespaces.NS_IDENTITY, bsn.getName())
- .addAttribute(Namespaces.ATTR_IDENTITY_TYPE, identity)
+ .addAttribute(Namespaces.ATTR_IDENTITY_TYPE, type)
.addAttribute(Namespaces.ATTR_VERSION, version);
if (singleton)
builder.addDirective(Namespaces.DIRECTIVE_SINGLETON, Boolean.TRUE.toString());
caps.add(builder.buildCapability());
}
+
+ private void doPlainJarIdentity(Resource resource, List<? super Capability> caps) {
+ String name = (String) resource.getProperties().get(Resource.NAME);
+ if (name.toLowerCase().endsWith(SUFFIX_JAR))
+ name = name.substring(0, name.length() - SUFFIX_JAR.length());
+
+ Version version = null;
+ int dashIndex = name.lastIndexOf('-');
+ if (dashIndex > 0) {
+ try {
+ String versionStr = name.substring(dashIndex + 1);
+ version = new Version(versionStr);
+ name = name.substring(0, dashIndex);
+ } catch (Exception e) {
+ version = null;
+ }
+ }
+
+ Builder builder = new Builder()
+ .setNamespace(Namespaces.NS_IDENTITY)
+ .addAttribute(Namespaces.NS_IDENTITY, name)
+ .addAttribute(Namespaces.ATTR_IDENTITY_TYPE, Namespaces.RESOURCE_TYPE_PLAIN_JAR);
+ if (version != null)
+ builder.addAttribute(Namespaces.ATTR_VERSION, version);
+ caps.add(builder.buildCapability());
+ }
void setStateLocal(GeneratorState state) {
this.state.set(state);
@@ -98,7 +139,7 @@ private GeneratorState getStateLocal() {
return state.get();
}
- private void doContent(Resource resource, List<? super Capability> capabilities) throws Exception {
+ private void doContent(Resource resource, MimeType mimeType, List<? super Capability> capabilities) throws Exception {
Builder builder = new Builder()
.setNamespace(Namespaces.NS_CONTENT);
@@ -111,7 +152,7 @@ private void doContent(Resource resource, List<? super Capability> capabilities)
long size = resource.getSize();
if (size > 0L) builder.addAttribute(Namespaces.ATTR_CONTENT_SIZE, size);
- builder.addAttribute(Namespaces.ATTR_CONTENT_MIME, MIME_TYPE_OSGI_BUNDLE);
+ builder.addAttribute(Namespaces.ATTR_CONTENT_MIME, mimeType.toString());
capabilities.add(builder.buildCapability());
}
@@ -47,7 +47,13 @@ public void setKnownBundlesExtra(Properties extras) {
}
public void analyzeResource(Resource resource, List<Capability> caps, List<Requirement> reqs) throws Exception {
- SymbolicName resourceName = Util.getSymbolicName(resource);
+ SymbolicName resourceName;
+ try {
+ resourceName = Util.getSymbolicName(resource);
+ } catch (IllegalArgumentException e) {
+ // not a bundle, so return without analyzing
+ return;
+ }
for (Enumeration<?> names = defaultProperties.propertyNames(); names.hasMoreElements(); ) {
String propName = (String) names.nextElement();
@@ -0,0 +1,18 @@
+package org.osgi.service.indexer.impl;
+
+public enum MimeType {
+ Bundle("application/vnd.osgi.bundle"),
+ Fragment("application/vnd.osgi.bundle"),
+ Jar("application/java-archive");
+
+ private String mimeType;
+
+ MimeType(String mimeType) {
+ this.mimeType = mimeType;
+ }
+
+ @Override
+ public String toString() {
+ return mimeType;
+ }
+}
@@ -49,7 +49,23 @@ public static Version getVersion(Resource resource) throws IOException {
Version version = (versionStr != null) ? new Version(versionStr) : Version.emptyVersion;
return version;
}
+
+ public static MimeType getMimeType(Resource resource) throws IOException {
+ Manifest manifest = resource.getManifest();
+ if (manifest == null)
+ return MimeType.Jar;
+ String bsn = manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME);
+ if (bsn == null)
+ return MimeType.Jar;
+
+ String fragmentHost = manifest.getMainAttributes().getValue(Constants.FRAGMENT_HOST);
+ if (fragmentHost != null)
+ return MimeType.Fragment;
+ return MimeType.Bundle;
+ }
+
+
public static void addVersionFilter(StringBuilder filter, VersionRange version, VersionKey key) {
if (version.isRange()) {
@@ -23,6 +23,7 @@
import junit.framework.TestCase;
import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
import org.osgi.framework.FrameworkUtil;
import org.osgi.service.indexer.Capability;
import org.osgi.service.indexer.Requirement;
@@ -329,4 +330,17 @@ public void testFragmentRequireBlueprintUsingHeader() throws Exception {
public void testFragmentBundleNativeCode() throws Exception {
assertFragmentMatch("testdata/fragment-19.txt", "testdata/19-bundlenativecode.jar");
}
+
+ public void testFragmentPlainJar() throws Exception {
+ LogService mockLog = Mockito.mock(LogService.class);
+ RepoIndex indexer = new RepoIndex(mockLog);
+ indexer.addAnalyzer(new KnownBundleAnalyzer(), FrameworkUtil.createFilter("(name=*)"));
+
+ assertFragmentMatch(indexer, "testdata/fragment-plainjar.txt", "testdata/jcip-annotations.jar");
+ Mockito.verifyZeroInteractions(mockLog);
+ }
+
+ public void testFragmentPlainJarWithVersion() throws Exception {
+ assertFragmentMatch("testdata/fragment-plainjar-versioned.txt", "testdata/jcip-annotations-2.5.6.wibble.jar");
+ }
}
@@ -0,0 +1,13 @@
+<resource>
+ <capability namespace='osgi.identity'>
+ <attribute name='osgi.identity' value='jcip-annotations'/>
+ <attribute name='type' value='jarfile'/>
+ <attribute name='version' type='Version' value='2.5.6.wibble'/>
+ </capability>
+ <capability namespace='osgi.content'>
+ <attribute name='osgi.content' value='15dab616e296ed2eb426e46c1b79615126197a5b9a2ee942bfa72b15c5e3dadd'/>
+ <attribute name='url' value='testdata/jcip-annotations-2.5.6.wibble.jar'/>
+ <attribute name='size' type='Long' value='2250'/>
+ <attribute name='mime' value='application/java-archive'/>
+ </capability>
+</resource>
@@ -0,0 +1,12 @@
+<resource>
+ <capability namespace='osgi.identity'>
+ <attribute name='osgi.identity' value='jcip-annotations'/>
+ <attribute name='type' value='jarfile'/>
+ </capability>
+ <capability namespace='osgi.content'>
+ <attribute name='osgi.content' value='15dab616e296ed2eb426e46c1b79615126197a5b9a2ee942bfa72b15c5e3dadd'/>
+ <attribute name='url' value='testdata/jcip-annotations.jar'/>
+ <attribute name='size' type='Long' value='2250'/>
+ <attribute name='mime' value='application/java-archive'/>
+ </capability>
+</resource>
@@ -75,5 +75,20 @@ public void testKnownBundlesExtra() throws Exception {
assertEquals(readStream(TestStandaloneLibrary.class.getResourceAsStream("/testdata/org.eclipse.equinox.ds-1.4.0.extra-fragment.txt")), writer.toString().trim());
deleteWithException(tempDir); }
+
+ public void testPlainJar() throws Exception {
+ RepoIndex indexer = new RepoIndex();
+
+ StringWriter writer = new StringWriter();
+ File tempDir = createTempDir();
+ File tempFile = copyToTempFile(tempDir, "testdata/jcip-annotations.jar");
+
+ Map<String, String> config = new HashMap<String, String>();
+ config.put(ResourceIndexer.ROOT_URL, tempDir.getAbsoluteFile().toURL().toString());
+ indexer.indexFragment(Collections.singleton(tempFile), writer, config);
+
+ assertEquals(readStream(TestStandaloneLibrary.class.getResourceAsStream("/testdata/plainjar.fragment.txt")), writer.toString().trim());
+
+ deleteWithException(tempDir); }
}
@@ -0,0 +1,12 @@
+<resource>
+ <capability namespace='osgi.identity'>
+ <attribute name='osgi.identity' value='jcip-annotations'/>
+ <attribute name='type' value='jarfile'/>
+ </capability>
+ <capability namespace='osgi.content'>
+ <attribute name='osgi.content' value='15dab616e296ed2eb426e46c1b79615126197a5b9a2ee942bfa72b15c5e3dadd'/>
+ <attribute name='url' value='testdata/jcip-annotations.jar'/>
+ <attribute name='size' type='Long' value='2250'/>
+ <attribute name='mime' value='application/java-archive'/>
+ </capability>
+</resource>

0 comments on commit e3f34f6

Please sign in to comment.