diff options
author | gjoranv <gv@verizonmedia.com> | 2019-10-18 09:18:46 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-10-18 09:18:46 +0200 |
commit | 4b1b720ba57cc016afe79f19f31e3983a7d3d58e (patch) | |
tree | 1ecc17e92ff93b801f86c94bd90274beccb68490 | |
parent | 09b9a84eeb6b2124c356bc1065fd54b596abb37e (diff) | |
parent | 951eeeb47ea79072cb1e77791d7c542cfed3785b (diff) |
Merge pull request #10994 from vespa-engine/gjoranv/bsnversion
Gjoranv/bsnversion
13 files changed, 465 insertions, 6 deletions
diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/core/BundleCollisionHook.java b/jdisc_core/src/main/java/com/yahoo/jdisc/core/BundleCollisionHook.java new file mode 100644 index 00000000000..58ad5df9b0d --- /dev/null +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/core/BundleCollisionHook.java @@ -0,0 +1,142 @@ +package com.yahoo.jdisc.core; + +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleEvent; +import org.osgi.framework.ServiceRegistration; +import org.osgi.framework.Version; +import org.osgi.framework.hooks.bundle.CollisionHook; +import org.osgi.framework.hooks.bundle.EventHook; +import org.osgi.framework.hooks.bundle.FindHook; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * A bundle {@link CollisionHook} that contains a set of bundles that are allowed to collide with + * bundles that are about to be installed. In order to clean up when bundles are uninstalled, this + * is also a bundle {@link EventHook}. + * + * Thread safe + * + * @author gjoranv + */ +public class BundleCollisionHook implements CollisionHook, EventHook, FindHook { + + private ServiceRegistration<?> registration; + private Map<Bundle, BsnVersion> allowedDuplicates = new HashMap<>(5); + + public void start(BundleContext context) { + if (registration != null) { + throw new IllegalStateException(); + } + String[] serviceClasses = {CollisionHook.class.getName(), EventHook.class.getName(), FindHook.class.getName()}; + registration = context.registerService(serviceClasses, this, null); + } + + public void stop() { + registration.unregister(); + registration = null; + } + + /** + * Adds a collection of bundles to the allowed duplicates. + */ + synchronized void allowDuplicateBundles(Collection<Bundle> bundles) { + for (var bundle : bundles) { + allowedDuplicates.put(bundle, new BsnVersion(bundle)); + } + } + + /** + * Cleans up the allowed duplicates when a bundle is uninstalled. + */ + @Override + public void event(BundleEvent event, Collection<BundleContext> contexts) { + if (event.getType() != BundleEvent.UNINSTALLED) return; + + synchronized (this) { + allowedDuplicates.remove(event.getBundle()); + } + } + + /** + * Removes duplicates of the allowed duplicate bundles from the given collision candidates. + */ + @Override + public synchronized void filterCollisions(int operationType, Bundle target, Collection<Bundle> collisionCandidates) { + Set<Bundle> whitelistedCandidates = new HashSet<>(); + for (var bundle : collisionCandidates) { + // This is O(n), but n should be small here, plus this is only called when bundles collide. + if (allowedDuplicates.containsValue(new BsnVersion(bundle))) { + whitelistedCandidates.add(bundle); + } + } + collisionCandidates.removeAll(whitelistedCandidates); + } + + /** + * Filters out the set of bundles that should not be visible to the bundle associated with the given context. + * If the given context represents one of the allowed duplicates, this method filters out all bundles + * that are duplicates of the allowed duplicates. Otherwise this method filters out the allowed duplicates, + * so they are not visible to other bundles. + * + * NOTE: This hook method is added for a consistent view of the installed bundles, but is not actively + * used by jdisc. The OSGi framework does not use FindHooks when calculating bundle wiring. + */ + @Override + public synchronized void find(BundleContext context, Collection<Bundle> bundles) { + Set<Bundle> bundlesToHide = new HashSet<>(); + if (allowedDuplicates.containsKey(context.getBundle())) { + for (var bundle : bundles) { + // isDuplicate... is O(n), but n should be small here, plus this is only run for duplicate bundles. + if (isDuplicateOfAllowedDuplicates(bundle)) { + bundlesToHide.add(bundle); + } + } + } else { + for (var bundle : bundles) { + if (allowedDuplicates.containsKey(bundle)) { + bundlesToHide.add(bundle); + } + } + } + bundles.removeAll(bundlesToHide); + } + + private boolean isDuplicateOfAllowedDuplicates(Bundle bundle) { + return ! allowedDuplicates.containsKey(bundle) && allowedDuplicates.containsValue(new BsnVersion(bundle)); + } + + + static class BsnVersion { + + private final String symbolicName; + private final Version version; + + BsnVersion(Bundle bundle) { + this.symbolicName = bundle.getSymbolicName(); + this.version = bundle.getVersion(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + BsnVersion that = (BsnVersion) o; + return Objects.equals(symbolicName, that.symbolicName) && + version.equals(that.version); + } + + @Override + public int hashCode() { + return Objects.hash(symbolicName, version); + } + + } + +} diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/core/FelixFramework.java b/jdisc_core/src/main/java/com/yahoo/jdisc/core/FelixFramework.java index 96fc0c91d2d..19a1707e97c 100644 --- a/jdisc_core/src/main/java/com/yahoo/jdisc/core/FelixFramework.java +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/core/FelixFramework.java @@ -15,6 +15,7 @@ import org.osgi.framework.wiring.FrameworkWiring; import java.io.File; import java.util.Arrays; +import java.util.Collection; import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -26,6 +27,7 @@ import java.util.logging.Logger; /** * @author Simon Thoresen Hult + * @author gjoranv */ public class FelixFramework implements OsgiFramework { @@ -35,11 +37,14 @@ public class FelixFramework implements OsgiFramework { private final ConsoleLogManager logListener; private final Felix felix; + private final BundleCollisionHook collisionHook; + @Inject public FelixFramework(FelixParams params) { deleteDirContents(new File(params.getCachePath())); felix = new Felix(params.toConfig()); logListener = params.isLoggerEnabled() ? new ConsoleLogManager() : null; + collisionHook = new BundleCollisionHook(); } @Override @@ -48,6 +53,7 @@ public class FelixFramework implements OsgiFramework { felix.start(); BundleContext ctx = felix.getBundleContext(); + collisionHook.start(ctx); logService.start(ctx); logHandler.install(ctx); if (logListener != null) { @@ -65,6 +71,7 @@ public class FelixFramework implements OsgiFramework { } logHandler.uninstall(); logService.stop(); + collisionHook.stop(); } felix.stop(); try { @@ -90,8 +97,8 @@ public class FelixFramework implements OsgiFramework { for (Bundle bundle : bundles) { if (!privileged && OsgiHeader.isSet(bundle, OsgiHeader.PRIVILEGED_ACTIVATOR)) { log.log(Level.INFO, "OSGi bundle '" + bundle.getSymbolicName() + "' " + - "states that it requires privileged " + - "initialization, but privileges are not available. YMMV."); + "states that it requires privileged " + + "initialization, but privileges are not available. YMMV."); } if (bundle.getHeaders().get(Constants.FRAGMENT_HOST) != null) { continue; // fragments can not be started @@ -102,7 +109,7 @@ public class FelixFramework implements OsgiFramework { } private String startedBundlesMessage(List<Bundle> bundles) { - StringBuilder sb = new StringBuilder("Started bundles: {" ); + StringBuilder sb = new StringBuilder("Started bundles: {"); for (Bundle b : bundles) sb.append("[" + b.getBundleId() + "]" + b.getSymbolicName() + ":" + b.getVersion() + ", "); sb.setLength(sb.length() - 2); @@ -127,9 +134,9 @@ public class FelixFramework implements OsgiFramework { }); try { long TIMEOUT_SECONDS = 60L; - if ( ! latch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS)) { + if (!latch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS)) { log.warning("No PACKAGES_REFRESHED FrameworkEvent received within " + TIMEOUT_SECONDS + - " seconds of calling FrameworkWiring.refreshBundles()"); + " seconds of calling FrameworkWiring.refreshBundles()"); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); @@ -146,6 +153,14 @@ public class FelixFramework implements OsgiFramework { return Arrays.asList(felix.getBundleContext().getBundles()); } + public List<Bundle> getBundles(Bundle requestingBundle) { + return Arrays.asList(requestingBundle.getBundleContext().getBundles()); + } + + public void allowDuplicateBundles(Collection<Bundle> bundles) { + collisionHook.allowDuplicateBundles(bundles); + } + private void installBundle(String bundleLocation, Set<String> mask, List<Bundle> out) throws BundleException { bundleLocation = BundleLocationResolver.resolve(bundleLocation); if (mask.contains(bundleLocation)) { diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/core/FelixParams.java b/jdisc_core/src/main/java/com/yahoo/jdisc/core/FelixParams.java index 9b877f68efd..0bca9388885 100644 --- a/jdisc_core/src/main/java/com/yahoo/jdisc/core/FelixParams.java +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/core/FelixParams.java @@ -56,6 +56,7 @@ public class FelixParams { ret.put(Constants.FRAMEWORK_SYSTEMPACKAGES, exportPackages.toString()); ret.put(Constants.SUPPORTS_BOOTCLASSPATH_EXTENSION, "true"); ret.put(Constants.FRAMEWORK_BOOTDELEGATION, "com.yourkit.runtime,com.yourkit.probes,com.yourkit.probes.builtin,com.singularity.*"); + ret.put(Constants.FRAMEWORK_BSNVERSION, Constants.FRAMEWORK_BSNVERSION_MANAGED); return ret; } } diff --git a/jdisc_core_test/integration_test/pom.xml b/jdisc_core_test/integration_test/pom.xml index 670d812c9e9..0b0a1ce81ef 100644 --- a/jdisc_core_test/integration_test/pom.xml +++ b/jdisc_core_test/integration_test/pom.xml @@ -153,6 +153,12 @@ </dependency> <dependency> <groupId>com.yahoo.vespa.jdisc_core</groupId> + <artifactId>cert-l1-dup</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.yahoo.vespa.jdisc_core</groupId> <artifactId>cert-l2</artifactId> <version>${project.version}</version> <scope>test</scope> @@ -165,6 +171,12 @@ </dependency> <dependency> <groupId>com.yahoo.vespa.jdisc_core</groupId> + <artifactId>cert-ml-dup</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.yahoo.vespa.jdisc_core</groupId> <artifactId>cert-nac</artifactId> <version>${project.version}</version> <scope>test</scope> diff --git a/jdisc_core_test/integration_test/src/test/java/com/yahoo/jdisc/core/BundleCollisionHookIntegrationTest.java b/jdisc_core_test/integration_test/src/test/java/com/yahoo/jdisc/core/BundleCollisionHookIntegrationTest.java new file mode 100644 index 00000000000..80de2a28322 --- /dev/null +++ b/jdisc_core_test/integration_test/src/test/java/com/yahoo/jdisc/core/BundleCollisionHookIntegrationTest.java @@ -0,0 +1,172 @@ +package com.yahoo.jdisc.core; + +import com.yahoo.jdisc.test.TestDriver; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleException; +import org.osgi.framework.launch.Framework; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import static com.yahoo.jdisc.core.FelixFrameworkIntegrationTest.startBundle; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * Note that the '-dup' bundles are necessary, because installing a bundle with the same location as an already + * installed bundle is a NOP. From the OSGi spec: "Every bundle is uniquely identified by its location string." + * + * @author gjoranv + */ +public class BundleCollisionHookIntegrationTest { + + private FelixFramework felix; + + @Before + public void startFelix() throws Exception { + felix = TestDriver.newOsgiFramework(); + felix.start(); + } + + @After + public void stopFelix() throws Exception { + felix.stop(); + } + + @Test + public void duplicate_bundles_cannot_be_installed_in_general() throws Exception { + startBundle(felix, "cert-l1.jar"); + try { + startBundle(felix, "cert-l1-dup.jar"); + fail("Expected exception due to duplicate bundles"); + } catch (BundleException e) { + assertTrue(e.getMessage().contains("Bundle symbolic name and version are not unique")); + } + } + + @Test + public void duplicate_bundles_can_be_installed_if_bsn_version_is_whitelisted() throws Exception { + Bundle bundleL = startBundle(felix, "cert-l1.jar"); + felix.allowDuplicateBundles(Collections.singleton(bundleL)); + + Bundle bundleLdup = startBundle(felix, "cert-l1-dup.jar"); + assertNotEquals(bundleL.getBundleId(), bundleLdup.getBundleId()); + } + + @Test + public void duplicates_whitelist_is_updated_when_bundles_are_uninstalled() throws Exception { + Bundle bundleL = startBundle(felix, "cert-l1.jar"); + felix.allowDuplicateBundles(Collections.singleton(bundleL)); + + startBundle(felix, "cert-l1-dup.jar"); + + // Remove the original bundle -> will also remove the allowed duplicate + bundleL.uninstall(); + + // Trigger error by trying to re-install the bundle while the duplicate remains + try { + startBundle(felix, "cert-l1.jar"); + fail("Expected exception due to duplicate bundles"); + } catch (BundleException e) { + assertTrue(e.getMessage().contains("Bundle symbolic name and version are not unique")); + } + } + + @Test + public void duplicates_whitelist_can_be_updated_with_additional_bundles() throws Exception { + Bundle bundleL = startBundle(felix, "cert-l1.jar"); + Bundle bundleMl = startBundle(felix, "cert-ml.jar"); + felix.allowDuplicateBundles(Collections.singleton(bundleL)); + felix.allowDuplicateBundles(Collections.singleton(bundleMl)); + + startBundle(felix, "cert-l1-dup.jar"); + startBundle(felix, "cert-ml-dup.jar"); + } + + @Test + public void allowed_duplicates_are_visible_to_the_framework_and_vice_versa() throws Exception { + Bundle bundleA = startBundle(felix, "cert-a.jar"); + Bundle bundleB = startBundle(felix, "cert-b.jar"); + + // Makes A and B visible to each other + felix.allowDuplicateBundles(Set.of(bundleA)); + felix.allowDuplicateBundles(Set.of(bundleB)); + + List<Bundle> visibleBundles = felix.getBundles(bundleA); + + // The framework bundle should always be visible (the FindHook does not remove it) + Bundle frameworkBundle = visibleBundles.get(0); + assertTrue(isFrameworkBundle(frameworkBundle)); + + // All bundles are always visible to the framework (this is according to the OSGi spec and handled by Felix) + List<Bundle> visibleToFramework = felix.getBundles(frameworkBundle); + assertEquals(3, visibleToFramework.size()); + } + + @Test + public void allowed_duplicates_are_visible_to_its_own_members() throws Exception { + Bundle bundleA = startBundle(felix, "cert-a.jar"); + Bundle bundleB = startBundle(felix, "cert-b.jar"); + + // Makes A and B visible to each other + felix.allowDuplicateBundles(Set.of(bundleA)); + felix.allowDuplicateBundles(Set.of(bundleB)); + + List<Bundle> visibleBundles = felix.getBundles(bundleA); + assertEquals(3, visibleBundles.size()); + assertSame(bundleA, visibleBundles.get(1)); + assertSame(bundleB, visibleBundles.get(2)); + } + + @Test + public void allowed_duplicates_are_invisible_to_unrelated_bundles() throws Exception { + Bundle bundleL = startBundle(felix, "cert-l1.jar"); + Bundle bundleA = startBundle(felix, "cert-a.jar"); + + // Makes L invisible to bundles outside the set of allowed duplicates + felix.allowDuplicateBundles(Set.of(bundleL)); + + List<Bundle> visibleBundles = felix.getBundles(bundleA); + assertEquals(2, visibleBundles.size()); + assertTrue(isFrameworkBundle(visibleBundles.get(0))); + assertSame(bundleA, visibleBundles.get(1)); + } + + @Test + public void set_of_allowed_duplicates_are_invisible_to_all_bundles_of_which_they_are_duplicates() throws Exception { + Bundle bundleL = startBundle(felix, "cert-l1.jar"); + + // Makes L invisible to bundles outside the set of allowed duplicates + felix.allowDuplicateBundles(Set.of(bundleL)); + Bundle bundleL2 = startBundle(felix, "cert-l1-dup.jar"); + + List<Bundle> visibleBundles = felix.getBundles(bundleL2); + assertEquals(2, visibleBundles.size()); + assertSame(bundleL2, visibleBundles.get(1)); + } + + @Test + public void allowed_duplicates_cannot_see_any_of_the_bundles_of_which_they_are_duplicates() throws Exception { + Bundle bundleL = startBundle(felix, "cert-l1.jar"); + + // Makes L invisible to bundles outside the set of allowed duplicates + felix.allowDuplicateBundles(Set.of(bundleL)); + Bundle invisibleToAllowedDuplicates = startBundle(felix, "cert-l1-dup.jar"); + + List<Bundle> visibleToAllowedDuplicates = felix.getBundles(bundleL); + assertEquals(2, visibleToAllowedDuplicates.size()); + assertSame(bundleL, visibleToAllowedDuplicates.get(1)); + } + + private boolean isFrameworkBundle(Bundle bundle) { + return (bundle == felix.bundleContext().getBundle() && (bundle instanceof Framework)); + } + +} diff --git a/jdisc_core_test/integration_test/src/test/java/com/yahoo/jdisc/core/FelixFrameworkIntegrationTest.java b/jdisc_core_test/integration_test/src/test/java/com/yahoo/jdisc/core/FelixFrameworkIntegrationTest.java index e8551b44a3c..9b7453d2d6b 100644 --- a/jdisc_core_test/integration_test/src/test/java/com/yahoo/jdisc/core/FelixFrameworkIntegrationTest.java +++ b/jdisc_core_test/integration_test/src/test/java/com/yahoo/jdisc/core/FelixFrameworkIntegrationTest.java @@ -111,8 +111,11 @@ public class FelixFrameworkIntegrationTest { Bundle bundleL = startBundle(felix, "cert-l1.jar"); Bundle bundleM = startBundle(felix, "cert-ml.jar"); assertEquals(1, callClass(bundleM, "com.yahoo.jdisc.bundle.m.CertificateM")); + + // Switch from l1 to l2 (identical bundles, except for bsn) bundleL.uninstall(); startBundle(felix, "cert-l2.jar"); + felix.refreshPackages(); assertEquals(2, callClass(bundleM, "com.yahoo.jdisc.bundle.m.CertificateM")); felix.stop(); @@ -185,7 +188,7 @@ public class FelixFrameworkIntegrationTest { "com.yahoo.vespa.jdisc_core.cert-q-frag"); } - private static Bundle startBundle(FelixFramework felix, String bundleLocation) throws BundleException { + static Bundle startBundle(FelixFramework felix, String bundleLocation) throws BundleException { List<Bundle> lst = felix.installBundle(bundleLocation); assertEquals(1, lst.size()); felix.startBundles(lst, false); diff --git a/jdisc_core_test/test_bundles/cert-l1-dup/.gitignore b/jdisc_core_test/test_bundles/cert-l1-dup/.gitignore new file mode 100644 index 00000000000..3cc25b51fc4 --- /dev/null +++ b/jdisc_core_test/test_bundles/cert-l1-dup/.gitignore @@ -0,0 +1,2 @@ +/pom.xml.build +/target diff --git a/jdisc_core_test/test_bundles/cert-l1-dup/pom.xml b/jdisc_core_test/test_bundles/cert-l1-dup/pom.xml new file mode 100644 index 00000000000..b1a61bc4145 --- /dev/null +++ b/jdisc_core_test/test_bundles/cert-l1-dup/pom.xml @@ -0,0 +1,36 @@ +<?xml version="1.0"?> +<!-- Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. --> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 + http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>com.yahoo.vespa.jdisc_core</groupId> + <artifactId>test_bundles</artifactId> + <version>7-SNAPSHOT</version> + </parent> + <artifactId>cert-l1-dup</artifactId> + <version>7-SNAPSHOT</version> + <packaging>bundle</packaging> + <name>${project.artifactId}</name> + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <Bundle-SymbolicName> + ${project.groupId}.cert-l1 + </Bundle-SymbolicName> + <Export-Package> + com.yahoo.jdisc.bundle.l + </Export-Package> + </instructions> + </configuration> + </plugin> + </plugins> + </build> +</project> diff --git a/jdisc_core_test/test_bundles/cert-l1-dup/src/main/java/com/yahoo/jdisc/bundle/l/CertificateL.java b/jdisc_core_test/test_bundles/cert-l1-dup/src/main/java/com/yahoo/jdisc/bundle/l/CertificateL.java new file mode 100644 index 00000000000..2060686ee4f --- /dev/null +++ b/jdisc_core_test/test_bundles/cert-l1-dup/src/main/java/com/yahoo/jdisc/bundle/l/CertificateL.java @@ -0,0 +1,15 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.bundle.l; + +import java.util.concurrent.Callable; + +/** + * @author Simon Thoresen Hult + */ +public class CertificateL implements Callable<Integer> { + + @Override + public Integer call() throws Exception { + return 11; + } +} diff --git a/jdisc_core_test/test_bundles/cert-ml-dup/.gitignore b/jdisc_core_test/test_bundles/cert-ml-dup/.gitignore new file mode 100644 index 00000000000..3cc25b51fc4 --- /dev/null +++ b/jdisc_core_test/test_bundles/cert-ml-dup/.gitignore @@ -0,0 +1,2 @@ +/pom.xml.build +/target diff --git a/jdisc_core_test/test_bundles/cert-ml-dup/pom.xml b/jdisc_core_test/test_bundles/cert-ml-dup/pom.xml new file mode 100644 index 00000000000..4382664c923 --- /dev/null +++ b/jdisc_core_test/test_bundles/cert-ml-dup/pom.xml @@ -0,0 +1,39 @@ +<?xml version="1.0"?> +<!-- Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. --> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 + http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>com.yahoo.vespa.jdisc_core</groupId> + <artifactId>test_bundles</artifactId> + <version>7-SNAPSHOT</version> + </parent> + <artifactId>cert-ml-dup</artifactId> + <version>7-SNAPSHOT</version> + <packaging>bundle</packaging> + <name>${project.artifactId}</name> + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <Bundle-SymbolicName> + ${project.groupId}.cert-ml + </Bundle-SymbolicName> + <Import-Package> + com.yahoo.jdisc.bundle.l + </Import-Package> + <Export-Package> + com.yahoo.jdisc.bundle.m + </Export-Package> + </instructions> + </configuration> + </plugin> + </plugins> + </build> +</project> diff --git a/jdisc_core_test/test_bundles/cert-ml-dup/src/main/java/com/yahoo/jdisc/bundle/m/CertificateM.java b/jdisc_core_test/test_bundles/cert-ml-dup/src/main/java/com/yahoo/jdisc/bundle/m/CertificateM.java new file mode 100644 index 00000000000..131c9e41a1e --- /dev/null +++ b/jdisc_core_test/test_bundles/cert-ml-dup/src/main/java/com/yahoo/jdisc/bundle/m/CertificateM.java @@ -0,0 +1,18 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.bundle.m; + +import java.util.concurrent.Callable; + +/** + * @author Simon Thoresen Hult + */ +public class CertificateM implements Callable<Integer> { + + @Override + @SuppressWarnings({ "unchecked" }) + public Integer call() throws Exception { + Class<?> certClass = Class.forName("com.yahoo.jdisc.bundle.l.CertificateL"); + Callable<Integer> cert = (Callable<Integer>)certClass.getDeclaredConstructor().newInstance(); + return cert.call(); + } +} diff --git a/jdisc_core_test/test_bundles/pom.xml b/jdisc_core_test/test_bundles/pom.xml index c11a94eacc5..d62d22c67f9 100644 --- a/jdisc_core_test/test_bundles/pom.xml +++ b/jdisc_core_test/test_bundles/pom.xml @@ -65,8 +65,10 @@ <module>cert-j-priv</module> <module>cert-k-pkgs</module> <module>cert-l1</module> + <module>cert-l1-dup</module> <module>cert-l2</module> <module>cert-ml</module> + <module>cert-ml-dup</module> <module>cert-nac</module> <module>cert-oa-path</module> <module>cert-p-jar</module> |