package org.apache.aries.subsystem.itests.defect; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.util.Arrays; import java.util.Collection; import java.util.EnumSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.jar.Attributes; import java.util.jar.Manifest; import org.apache.aries.subsystem.AriesSubsystem; import org.apache.aries.subsystem.core.archive.AriesProvisionDependenciesDirective; import org.apache.aries.subsystem.core.archive.SubsystemTypeHeader; import org.apache.aries.subsystem.itests.SubsystemTest; import org.apache.aries.subsystem.itests.util.BundleArchiveBuilder; import org.apache.aries.subsystem.itests.util.SubsystemArchiveBuilder; import org.apache.aries.subsystem.itests.util.TestCapability; import org.apache.aries.subsystem.itests.util.TestRepository; import org.apache.aries.subsystem.itests.util.TestRepositoryContent; import org.apache.aries.subsystem.itests.util.TestRequirement; import org.easymock.internal.matchers.Null; import org.junit.Test; import org.ops4j.pax.tinybundles.core.InnerClassStrategy; import org.ops4j.pax.tinybundles.core.TinyBundles; import org.osgi.framework.Bundle; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.osgi.framework.Version; import org.osgi.framework.hooks.resolver.ResolverHook; import org.osgi.framework.hooks.resolver.ResolverHookFactory; import org.osgi.framework.namespace.BundleNamespace; import org.osgi.framework.namespace.IdentityNamespace; import org.osgi.framework.namespace.PackageNamespace; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; import org.osgi.service.repository.Repository; import org.osgi.service.subsystem.Subsystem; import org.osgi.service.subsystem.Subsystem.State; import org.osgi.service.subsystem.SubsystemConstants; import org.osgi.service.subsystem.SubsystemException; /* * https://issues.apache.org/jira/browse/ARIES-1383 * * Provide option to disable the provisioning of dependencies at install time. * * For tests containing a numerical value in the name, see the description of * ARIES-1383 for an explanation. */ public class Aries1383Test extends SubsystemTest { private static final String SYMBOLICNAME_PREFIX = Aries1383Test.class.getSimpleName() + '.'; private static final String APPLICATION_A = SYMBOLICNAME_PREFIX + "application.a"; private static final String APPLICATION_B = SYMBOLICNAME_PREFIX + "application.b"; private static final String APPLICATION_DEPENDENCY_IN_ARCHIVE = SYMBOLICNAME_PREFIX + "application.dependency.in.archive"; private static final String APPLICATION_EMPTY = SYMBOLICNAME_PREFIX + "application.empty"; private static final String APPLICATION_INSTALL_FAILED = SYMBOLICNAME_PREFIX + "application.install.failed"; private static final String APPLICATION_INVALID_PROVISION_DEPENDENCIES = SYMBOLICNAME_PREFIX + "application.invalid.provision.dependency"; private static final String APPLICATION_MISSING_DEPENDENCY = SYMBOLICNAME_PREFIX + "application.missing.dependency"; private static final String APPLICATION_PROVISION_DEPENDENCIES_INSTALL = SYMBOLICNAME_PREFIX + "application.provision.dependencies.install"; private static final String APPLICATION_START_FAILURE = SYMBOLICNAME_PREFIX + "application.start.failure"; private static final String BUNDLE_A = SYMBOLICNAME_PREFIX + "bundle.a"; private static final String BUNDLE_B = SYMBOLICNAME_PREFIX + "bundle.b"; private static final String BUNDLE_C = SYMBOLICNAME_PREFIX + "bundle.c"; private static final String BUNDLE_D = SYMBOLICNAME_PREFIX + "bundle.d"; private static final String BUNDLE_INVALID_MANIFEST = SYMBOLICNAME_PREFIX + "bundle.invalid.manifest"; private static final String BUNDLE_START_FAILURE = SYMBOLICNAME_PREFIX + "bundle.start.failure"; private static final String ESA_EXTENSION = ".esa"; private static final String FEATURE_PROVISION_DEPENDENCIES_INSTALL = "feature.provision.dependencies.install"; private static final String FEATURE_PROVISION_DEPENDENCIES_RESOLVE = "feature.provision.dependencies.resolve"; private static final String JAR_EXTENSION = ".jar"; private static final String MANIFEST_VERSION = "1.0"; private static final String PACKAGE_A = SYMBOLICNAME_PREFIX + "a"; private static final String PACKAGE_B = SYMBOLICNAME_PREFIX + "b"; private static final String PACKAGE_C = SYMBOLICNAME_PREFIX + "c"; private static final String PACKAGE_D = SYMBOLICNAME_PREFIX + "d"; private static final String SUBSYSTEM_MANIFEST_FILE = "OSGI-INF/SUBSYSTEM.MF"; /* * (1) A set of subsystems with interleaving content dependencies are able * to be independently, simultaneously, and successfully installed and * started. */ @Test public void test1() throws Exception { Subsystem root = getRootSubsystem(); final Subsystem c1 = installSubsystem( root, "c1", new SubsystemArchiveBuilder() .symbolicName("c1") .type(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()) .build(), false ); uninstallableSubsystems.add(c1); c1.start(); stoppableSubsystems.add(c1); @SuppressWarnings("unchecked") Callable<Subsystem>[] installCallables = new Callable[] { new Callable<Subsystem>() { @Override public Subsystem call() throws Exception { Subsystem result = installSubsystem( c1, "a1", new SubsystemArchiveBuilder() .symbolicName("a1") .type(SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()) .content("b1") .bundle( "b1", new BundleArchiveBuilder() .symbolicName("b1") .importPackage("b2") .build()) .build(), false); uninstallableSubsystems.add(result); return result; } }, new Callable<Subsystem>() { @Override public Subsystem call() throws Exception { Subsystem result = installSubsystem( c1, "f1", new SubsystemArchiveBuilder() .symbolicName("f1") .type(SubsystemConstants.SUBSYSTEM_TYPE_FEATURE + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()) .content("b2") .bundle( "b2", new BundleArchiveBuilder() .symbolicName("b2") .exportPackage("b2") .importPackage("b3") .build()) .build(), false); uninstallableSubsystems.add(result); return result; } }, new Callable<Subsystem>() { @Override public Subsystem call() throws Exception { Subsystem result = installSubsystem( c1, "f2", new SubsystemArchiveBuilder() .symbolicName("f2") .type(SubsystemConstants.SUBSYSTEM_TYPE_FEATURE + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()) .content("b4") .bundle( "b4", new BundleArchiveBuilder() .symbolicName("b4") .exportPackage("b4") .importPackage("b2") .importPackage("b3") .build()) .build(), false); uninstallableSubsystems.add(result); return result; } }, new Callable<Subsystem>() { @Override public Subsystem call() throws Exception { Subsystem result = installSubsystem( c1, "c2", new SubsystemArchiveBuilder() .symbolicName("c2") .type(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()) .content("b3;version=\"[0,0]\"") .exportPackage("b3") .importPackage("b4") .bundle( "b3", new BundleArchiveBuilder() .symbolicName("b3") .exportPackage("b3") .importPackage("b4") .build()) .build(), false); uninstallableSubsystems.add(result); return result; } } }; ExecutorService executor = Executors.newFixedThreadPool(4); List<Future<Subsystem>> installFutures = executor.invokeAll(Arrays.asList(installCallables)); final Subsystem a1 = installFutures.get(0).get(); assertConstituent(a1, "b1"); final Subsystem f1 = installFutures.get(1).get(); assertConstituent(f1, "b2"); final Subsystem f2 = installFutures.get(2).get(); assertConstituent(f2, "b4"); final Subsystem c2 = installFutures.get(3).get(); assertConstituent(c2, "b3"); @SuppressWarnings("unchecked") Callable<Null>[] startCallables = new Callable[] { new Callable<Null>() { @Override public Null call() throws Exception { a1.start(); assertEvent(a1, State.INSTALLED, subsystemEvents.poll(a1.getSubsystemId(), 5000)); assertEvent(a1, State.RESOLVING, subsystemEvents.poll(a1.getSubsystemId(), 5000)); assertEvent(a1, State.RESOLVED, subsystemEvents.poll(a1.getSubsystemId(), 5000)); stoppableSubsystems.add(a1); return null; } }, new Callable<Null>() { @Override public Null call() throws Exception { f1.start(); assertEvent(f1, State.INSTALLED, subsystemEvents.poll(f1.getSubsystemId(), 5000)); assertEvent(f1, State.RESOLVING, subsystemEvents.poll(f1.getSubsystemId(), 5000)); assertEvent(f1, State.RESOLVED, subsystemEvents.poll(f1.getSubsystemId(), 5000)); stoppableSubsystems.add(f1); return null; } }, new Callable<Null>() { @Override public Null call() throws Exception { f2.start(); assertEvent(f2, State.INSTALLED, subsystemEvents.poll(f2.getSubsystemId(), 5000)); assertEvent(f2, State.RESOLVING, subsystemEvents.poll(f2.getSubsystemId(), 5000)); assertEvent(f2, State.RESOLVED, subsystemEvents.poll(f2.getSubsystemId(), 5000)); stoppableSubsystems.add(f2); return null; } }, new Callable<Null>() { @Override public Null call() throws Exception { c2.start(); assertEvent(c2, State.INSTALLED, subsystemEvents.poll(c2.getSubsystemId(), 5000)); assertEvent(c2, State.RESOLVING, subsystemEvents.poll(c2.getSubsystemId(), 5000)); assertEvent(c2, State.RESOLVED, subsystemEvents.poll(c2.getSubsystemId(), 5000)); stoppableSubsystems.add(c2); return null; } } }; List<Future<Null>> startFutures = executor.invokeAll(Arrays.asList(startCallables)); startFutures.get(0).get(); startFutures.get(1).get(); startFutures.get(2).get(); startFutures.get(3).get(); } /* * (2) Subsystem with apache-aries-provision-dependencies:=resolve is in the * INSTALLING state after a successful installation. */ @Test public void test2() throws Exception { Subsystem root = getRootSubsystem(); Subsystem subsystem = installSubsystem(root, APPLICATION_EMPTY, applicationEmpty(), false); try { assertState(State.INSTALLING, subsystem); } finally { uninstallSubsystemSilently(subsystem); } } /* * (3) Subsystem with apache-aries-provision-dependencies:=resolve is available * as a service after a successful installation. */ @Test public void test3() throws Exception { Subsystem root = getRootSubsystem(); Subsystem subsystem = installSubsystem(root, APPLICATION_EMPTY, applicationEmpty(), false); try { assertReferences( Subsystem.class, "(&(subsystem.symbolicName=" + APPLICATION_EMPTY + ")(subsystem.version=0.0.0)(subsystem.type=" + SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ")(subsystem.state=" + State.INSTALLING + "))", 1); assertReferences( AriesSubsystem.class, "(&(subsystem.symbolicName=" + APPLICATION_EMPTY + ")(subsystem.version=0.0.0)(subsystem.type=" + SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ")(subsystem.state=" + State.INSTALLING + "))", 1); } finally { uninstallSubsystemSilently(subsystem); } } /* * (4) Subsystem with apache-aries-provision-dependencies:=resolve does not * have its dependencies installed after a successful installation. */ @Test public void test4() throws Exception { Subsystem root = getRootSubsystem(); Subsystem subsystem = installSubsystem(root, APPLICATION_DEPENDENCY_IN_ARCHIVE, applicationDependencyInArchive(), false); try { assertConstituent(subsystem, BUNDLE_A); assertNotConstituent(subsystem, BUNDLE_B); assertNotConstituent(root, BUNDLE_B); } finally { uninstallSubsystemSilently(subsystem); } } /* * (5) Subsystem with apache-aries-provision-dependencies:=resolve undergoes * the following state transitions when starting: INSTALLING -> INSTALLED * -> RESOLVING -> RESOLVED -> STARTING -> ACTIVE. */ @Test public void test5() throws Exception { Subsystem root = getRootSubsystem(); subsystemEvents.clear(); Subsystem subsystem = root.install( "application", new SubsystemArchiveBuilder() .header(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, "application") .header(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()) .build() ); try { long id = subsystem.getSubsystemId(); assertEvent(subsystem, State.INSTALLING, subsystemEvents.poll(id, 5000)); assertNull(subsystemEvents.poll(id, 1)); subsystem.start(); try { assertEvent(subsystem, State.INSTALLED, subsystemEvents.poll(id, 5000)); assertEvent(subsystem, State.RESOLVING, subsystemEvents.poll(id, 5000)); assertEvent(subsystem, State.RESOLVED, subsystemEvents.poll(id, 5000)); assertEvent(subsystem, State.STARTING, subsystemEvents.poll(id, 5000)); assertEvent(subsystem, State.ACTIVE, subsystemEvents.poll(id, 5000)); assertNull(subsystemEvents.poll(id, 1)); } finally { stopSubsystemSilently(subsystem); } } finally { uninstallSubsystemSilently(subsystem); } } /* * (6) Subsystem with apache-aries-provision-dependencies:=resolve has its * dependencies installed after a successful start. */ @Test public void test6() throws Exception { Subsystem root = getRootSubsystem(); Subsystem subsystem = root.install( "application", new SubsystemArchiveBuilder() .symbolicName("application") .type(SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()) .content("bundle1") .bundle( "bundle1", new BundleArchiveBuilder() .symbolicName("bundle1") .exportPackage("a") .importPackage("b") .build()) .bundle( "bundle2", new BundleArchiveBuilder() .symbolicName("bundle2") .exportPackage("b") .build()) .build() ); try { assertNotConstituent(root, "bundle2"); startSubsystem(subsystem, false); try { assertConstituent(root, "bundle2"); } finally { stopSubsystemSilently(subsystem); } } finally { uninstallSubsystemSilently(subsystem); } } /* * (7) Subsystem with apache-aries-provision-dependencies:=resolve is in the * INSTALL_FAILED state after an unsuccessful installation. */ @Test public void test7() throws Exception { Subsystem root = getRootSubsystem(); subsystemEvents.clear(); try { Subsystem subsystem = root.install(APPLICATION_INSTALL_FAILED, applicationInstallFailed()); uninstallSubsystemSilently(subsystem); fail("Subsystem should not have installed"); } catch (SubsystemException e) { e.printStackTrace(); long id = lastSubsystemId(); assertEvent(id, APPLICATION_INSTALL_FAILED, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.INSTALLING, subsystemEvents.poll(id, 5000), ServiceEvent.REGISTERED); assertEvent(id, APPLICATION_INSTALL_FAILED, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.INSTALL_FAILED, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, APPLICATION_INSTALL_FAILED, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.UNINSTALLING, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, APPLICATION_INSTALL_FAILED, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.UNINSTALLED, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); } } /* * (8) Subsystem with apache-aries-provision-dependencies:=resolve is not * available as a service after an unsuccessful installation. */ @Test public void test8() throws Exception { Subsystem root = getRootSubsystem(); try { Subsystem subsystem = installSubsystem(root, APPLICATION_INSTALL_FAILED, applicationInstallFailed(), false); uninstallSubsystemSilently(subsystem); fail("Subsystem should not have installed"); } catch (SubsystemException e) { e.printStackTrace(); assertEquals("Subsystem service should not exist", 0, bundleContext.getServiceReferences( Subsystem.class, "(" + SubsystemConstants.SUBSYSTEM_ID_PROPERTY + "=" + lastSubsystemId() + ")" ).size()); } } /* * (9) Subsystem with apache-aries-provision-dependencies:=resolve is in the * INSTALLING state when dependencies cannot be provisioned after invoking * the start method. */ @Test public void test9() throws Exception { Subsystem root = getRootSubsystem(); Subsystem subsystem = installSubsystem(root, APPLICATION_MISSING_DEPENDENCY, applicationMissingDependency(), false); try { startSubsystem(subsystem, false); stopSubsystemSilently(subsystem); fail("Subsystem should not have started"); } catch (SubsystemException e) { e.printStackTrace(); assertState(State.INSTALLING, subsystem); } finally { uninstallSubsystemSilently(subsystem); } } /* * (10) Subsystem fails installation if the apache-aries-provision-dependencies * directive has a value other than "install" or "resolve". */ @Test public void test10() throws Exception { Subsystem root = getRootSubsystem(); try { Subsystem subsystem = installSubsystem( root, APPLICATION_INVALID_PROVISION_DEPENDENCIES, applicationInvalidProvisionDependencies(), false); uninstallSubsystemSilently(subsystem); fail("Subsystem should not have installed"); } catch (SubsystemException e) { e.printStackTrace(); } } /* * (11) Subsystem with apache-aries-provision-dependencies:=resolve undergoes * the following state transitions when starting fails due to a runtime * resolution failure: INSTALLING -> INSTALLED -> RESOLVING -> INSTALLED. */ @Test public void test11() throws Exception { Subsystem root = getRootSubsystem(); subsystemEvents.clear(); Subsystem subsystem = root.install(APPLICATION_DEPENDENCY_IN_ARCHIVE, applicationDependencyInArchive()); ServiceRegistration<ResolverHookFactory> registration = bundleContext.registerService( ResolverHookFactory.class, new ResolverHookFactory() { @Override public ResolverHook begin(Collection<BundleRevision> triggers) { return new ResolverHook() { @Override public void filterResolvable(Collection<BundleRevision> candidates) { for (Iterator<BundleRevision> i = candidates.iterator(); i.hasNext();) { BundleRevision revision = i.next(); if (revision.getSymbolicName().equals(BUNDLE_B)) { i.remove(); } } } @Override public void filterSingletonCollisions( BundleCapability singleton, Collection<BundleCapability> collisionCandidates) { // Nothing. } @Override public void filterMatches( BundleRequirement requirement, Collection<BundleCapability> candidates) { // Nothing. } @Override public void end() { // Nothing. } }; } }, null ); try { subsystem.start(); stopSubsystemSilently(subsystem); fail("Subsystem should not have started"); } catch (SubsystemException e) { e.printStackTrace(); long id = lastSubsystemId(); assertEvent(id, APPLICATION_DEPENDENCY_IN_ARCHIVE, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.INSTALLING, subsystemEvents.poll(id, 5000), ServiceEvent.REGISTERED); assertEvent(id, APPLICATION_DEPENDENCY_IN_ARCHIVE, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.INSTALLED, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, APPLICATION_DEPENDENCY_IN_ARCHIVE, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.RESOLVING, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, APPLICATION_DEPENDENCY_IN_ARCHIVE, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.INSTALLED, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); } finally { registration.unregister(); uninstallSubsystemSilently(subsystem); } } /* * (12) Subsystem with apache-aries-provision-dependencies:=resolve undergoes * the following state transitions when starting fails due to a start * failure: INSTALLING -> INSTALLED -> RESOLVING -> RESOLVED -> STARTING -> * RESOLVED. */ @Test public void test12() throws Exception { Subsystem root = getRootSubsystem(); subsystemEvents.clear(); Subsystem subsystem = root.install(APPLICATION_START_FAILURE, applicationStartFailure()); try { subsystem.start(); stopSubsystemSilently(subsystem); fail("Subsystem should not have started"); } catch (SubsystemException e) { e.printStackTrace(); long id = lastSubsystemId(); assertEvent(id, APPLICATION_START_FAILURE, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.INSTALLING, subsystemEvents.poll(id, 5000), ServiceEvent.REGISTERED); assertEvent(id, APPLICATION_START_FAILURE, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.INSTALLED, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, APPLICATION_START_FAILURE, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.RESOLVING, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, APPLICATION_START_FAILURE, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.RESOLVED, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, APPLICATION_START_FAILURE, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.STARTING, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, APPLICATION_START_FAILURE, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.RESOLVED, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); } finally { uninstallSubsystemSilently(subsystem); } } /* * (13) The root subsystem has apache-aries-provision-dependencies:=install. */ @Test public void test13() throws Exception { Subsystem root = getRootSubsystem(); Map<String, String> headers = root.getSubsystemHeaders(null); String headerStr = headers.get(SubsystemConstants.SUBSYSTEM_TYPE); SubsystemTypeHeader header = new SubsystemTypeHeader(headerStr); AriesProvisionDependenciesDirective directive = header.getAriesProvisionDependenciesDirective(); assertEquals( "Wrong directive", AriesProvisionDependenciesDirective.INSTALL, directive); } /* * (14) Subsystem with explicit apache-aries-provision-dependencies:=install * works as before. */ @Test public void test14() throws Exception { Subsystem root = getRootSubsystem(); Subsystem subsystem = installSubsystem(root, APPLICATION_PROVISION_DEPENDENCIES_INSTALL, applicationProvisionDependenciesInstall(), true); try { assertConstituent(subsystem, BUNDLE_A); assertConstituent(root, BUNDLE_B); startSubsystem(subsystem, true); stopSubsystem(subsystem); } finally { uninstallSubsystem(subsystem); } } /* * (15) Unscoped subsystem with a value of apache-aries-provision-dependencies * that is different than the scoped parent fails installation. */ @Test public void test15a() throws Exception { Subsystem root = getRootSubsystem(); try { Subsystem subsystem = installSubsystem(root, FEATURE_PROVISION_DEPENDENCIES_RESOLVE, featureProvisionDependenciesResolve(), false); uninstallSubsystemSilently(subsystem); fail("Subsystem should not have installed"); } catch (SubsystemException e) { e.printStackTrace(); } } /* * (15) Unscoped subsystem with a value of apache-aries-provision-dependencies * that is different than the scoped parent fails installation. */ @Test public void test15b() throws Exception { Subsystem root = getRootSubsystem(); Subsystem application = installSubsystem(root, APPLICATION_PROVISION_DEPENDENCIES_INSTALL, applicationProvisionDependenciesInstall(), true); try { Subsystem feature = installSubsystem(application, FEATURE_PROVISION_DEPENDENCIES_RESOLVE, featureProvisionDependenciesResolve(), false); uninstallSubsystemSilently(feature); fail("Subsystem should not have installed"); } catch (SubsystemException e) { e.printStackTrace(); } finally { uninstallSubsystemSilently(application); } } /* * (16) Unscoped subsystem with a value of apache-aries-provision-dependencies * that is the same as the scoped parent installs successfully. */ @Test public void test16a() throws Exception { Subsystem root = getRootSubsystem(); try { Subsystem subsystem = installSubsystem( root, FEATURE_PROVISION_DEPENDENCIES_INSTALL, new SubsystemArchiveBuilder() .symbolicName("application") .type(SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.INSTALL.toString()) .build(), true); uninstallSubsystemSilently(subsystem); } catch (SubsystemException e) { e.printStackTrace(); fail("Subsystem should have installed"); } } /* * (16) Unscoped subsystem with a value of apache-aries-provision-dependencies * that is the same as the scoped parent installs successfully. */ @Test public void test16b() throws Exception { Subsystem root = getRootSubsystem(); Subsystem application = installSubsystem( root, "application", new SubsystemArchiveBuilder() .symbolicName("application") .type(SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.INSTALL.toString()) .build(), true); try { Subsystem feature = installSubsystem( application, "feature", new SubsystemArchiveBuilder() .symbolicName("feature") .type(SubsystemConstants.SUBSYSTEM_TYPE_FEATURE + ';' + AriesProvisionDependenciesDirective.INSTALL.toString()) .build(), true); uninstallSubsystemSilently(feature); } catch (SubsystemException e) { e.printStackTrace(); fail("Subsystem should have installed"); } finally { uninstallSubsystemSilently(application); } } /* * (16) Unscoped subsystem with a value of apache-aries-provision-dependencies * that is the same as the scoped parent installs successfully. */ @Test public void test16c() throws Exception { Subsystem root = getRootSubsystem(); try { Subsystem subsystem = installSubsystem( root, "application", new SubsystemArchiveBuilder() .symbolicName("application") .type(SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()) .subsystem( "feature", new SubsystemArchiveBuilder() .symbolicName("feature") .type(SubsystemConstants.SUBSYSTEM_TYPE_FEATURE + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()) .build()) .build(), false); uninstallSubsystemSilently(subsystem); } catch (SubsystemException e) { e.printStackTrace(); fail("Subsystem should have installed"); } } /* * (17) Scoped subsystem with a value of apache-aries-provision-dependencies * that is the same as the scoped parent behaves accordingly. */ @Test public void test17() throws Exception { Subsystem root = getRootSubsystem(); subsystemEvents.clear(); Subsystem parent = root.install(APPLICATION_B, applicationB()); try { long id = parent.getSubsystemId(); assertEvent(id, APPLICATION_B, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.INSTALLING, subsystemEvents.poll(id, 5000), ServiceEvent.REGISTERED); assertNull("Unexpected event", subsystemEvents.poll(id, 1)); assertNotConstituent(root, BUNDLE_B); assertConstituent(parent, BUNDLE_A); Subsystem child = getChild(parent, APPLICATION_A); assertNotNull("Missing child", child); id = child.getSubsystemId(); assertEvent(id, APPLICATION_A, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.INSTALLING, subsystemEvents.poll(id, 5000), ServiceEvent.REGISTERED); assertNull("Unexpected event", subsystemEvents.poll(id, 1)); assertNotConstituent(root, BUNDLE_D); assertConstituent(child, BUNDLE_A); assertConstituent(child, BUNDLE_C); parent.start(); try { id = parent.getSubsystemId(); assertEvent(id, APPLICATION_B, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.INSTALLED, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, APPLICATION_B, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.RESOLVING, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, APPLICATION_B, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.RESOLVED, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, APPLICATION_B, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.STARTING, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, APPLICATION_B, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.ACTIVE, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertNull("Unexpected event", subsystemEvents.poll(id, 1)); assertConstituent(root, BUNDLE_B); id = child.getSubsystemId(); assertEvent(id, APPLICATION_A, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.INSTALLED, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, APPLICATION_A, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.RESOLVING, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, APPLICATION_A, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.RESOLVED, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, APPLICATION_A, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.STARTING, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, APPLICATION_A, Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.ACTIVE, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertNull("Unexpected event", subsystemEvents.poll(id, 1)); assertConstituent(root, BUNDLE_D); } finally { stopSubsystemSilently(parent); } } finally { uninstallSubsystemSilently(parent); } } /* * (18) Scoped subsystem with a value of apache-aries-provision-dependencies * that overrides the scoped parent behaves accordingly. */ @Test public void test18() throws Exception { Subsystem root = getRootSubsystem(); subsystemEvents.clear(); Subsystem parent = root.install( "parent", new SubsystemArchiveBuilder() .symbolicName("parent") .type(SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.INSTALL.toString() + ';' + SubsystemConstants.PROVISION_POLICY_DIRECTIVE + ":=" + SubsystemConstants.PROVISION_POLICY_ACCEPT_DEPENDENCIES) .content("bundle1") .bundle( "bundle1", new BundleArchiveBuilder() .symbolicName("bundle1") .importPackage("a") .build()) .bundle( "bundle2", new BundleArchiveBuilder() .symbolicName("bundle2") .exportPackage("a") .build()) .build() ); try { long id = parent.getSubsystemId(); assertEvent(id, "parent", Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.INSTALLING, subsystemEvents.poll(id, 5000), ServiceEvent.REGISTERED); assertEvent(id, "parent", Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.INSTALLED, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertNull("Unexpected event", subsystemEvents.poll(id, 1)); assertConstituent(parent, "bundle2"); assertConstituent(parent, "bundle1"); parent.start(); Subsystem child = parent.install( "child", new SubsystemArchiveBuilder() .symbolicName("child") .type(SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()) .content("bundle3") .bundle( "bundle3", new BundleArchiveBuilder() .symbolicName("bundle3") .importPackage("b") .build()) .bundle( "bundle4", new BundleArchiveBuilder() .symbolicName("bundle4") .exportPackage("b") .build()) .build() ); id = child.getSubsystemId(); assertEvent(id, "child", Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.INSTALLING, subsystemEvents.poll(id, 5000), ServiceEvent.REGISTERED); assertNull("Unexpected event", subsystemEvents.poll(id, 1)); assertNotConstituent(parent, "bundle4"); assertConstituent(child, "bundle3"); child.start(); try { id = parent.getSubsystemId(); assertEvent(id, "parent", Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.RESOLVING, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, "parent", Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.RESOLVED, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, "parent", Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.STARTING, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, "parent", Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.ACTIVE, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertNull("Unexpected event", subsystemEvents.poll(id, 1)); id = child.getSubsystemId(); assertEvent(id, "child", Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.INSTALLED, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, "child", Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.RESOLVING, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, "child", Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.RESOLVED, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, "child", Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.STARTING, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, "child", Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.ACTIVE, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertNull("Unexpected event", subsystemEvents.poll(id, 1)); assertConstituent(parent, "bundle4"); } finally { stopSubsystemSilently(parent); } } finally { uninstallSubsystemSilently(parent); } } /* * (19) Scoped subsystem with only features as parents is able to override * the value of apache-aries-provision-dependencies. */ @Test public void test19() throws Exception { Subsystem root = getRootSubsystem(); subsystemEvents.clear(); Subsystem feature1 = installSubsystem( root, "feature1", new SubsystemArchiveBuilder() .symbolicName("feature1") .type(SubsystemConstants.SUBSYSTEM_TYPE_FEATURE) .build() ); try { Subsystem feature2 = installSubsystem( root, "feature2", new SubsystemArchiveBuilder() .symbolicName("feature2") .type(SubsystemConstants.SUBSYSTEM_TYPE_FEATURE + ';' + AriesProvisionDependenciesDirective.INSTALL.toString()) .build() ); try { SubsystemArchiveBuilder applicationArchive = new SubsystemArchiveBuilder() .symbolicName("application") .type(SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString() + ';' + SubsystemConstants.PROVISION_POLICY_DIRECTIVE + ":=" + SubsystemConstants.PROVISION_POLICY_ACCEPT_DEPENDENCIES) .content("bundle1") .bundle( "bundle1", new BundleArchiveBuilder() .symbolicName("bundle1") .importPackage("a") .build()) .bundle( "bundle2", new BundleArchiveBuilder() .symbolicName("bundle2") .exportPackage("a") .build()); Subsystem application1 = feature1.install("application", applicationArchive.build()); Subsystem application2 = feature2.install("application", applicationArchive.build()); assertSame("Wrong subsystem", application1, application2); assertEquals("Wrong subsystem", application1, application2); assertChild(feature1, "application"); assertChild(feature2, "application"); long id = application1.getSubsystemId(); assertEvent(id, "application", Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.INSTALLING, subsystemEvents.poll(id, 5000), ServiceEvent.REGISTERED); assertNull("Unexpected event", subsystemEvents.poll(id, 1)); assertConstituent(application1, "bundle1"); assertNotConstituent(application1, "bundle2"); application1.start(); try { assertEvent(id, "application", Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.INSTALLED, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, "application", Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.RESOLVING, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, "application", Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.RESOLVED, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, "application", Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.STARTING, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertEvent(id, "application", Version.emptyVersion, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION, State.ACTIVE, subsystemEvents.poll(id, 5000), ServiceEvent.MODIFIED); assertNull("Unexpected event", subsystemEvents.poll(id, 1)); assertConstituent(application1, "bundle2"); } finally { stopSubsystemSilently(application1); } } finally { uninstallSubsystemSilently(feature2); } } finally { uninstallSubsystemSilently(feature1); } } /* * (20) Install a scoped subsystem, S1, with * apache-aries-provision-dependencies:=resolve. Install two features, F1 and * F2, independently as children of S1. F1 has bundle B1 as content. F2 has * bundle B2 as content. B2 has B1 as a dependency. B1 should be a * constituent of F1 but not of the root subsystem. */ @Test public void test20() throws Exception { serviceRegistrations.add(bundleContext.registerService( Repository.class, new TestRepository.Builder() .resource(new TestRepositoryContent.Builder() .capability(new TestCapability.Builder() .namespace(IdentityNamespace.IDENTITY_NAMESPACE) .attribute( IdentityNamespace.IDENTITY_NAMESPACE, "b1") .attribute( IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, Version.emptyVersion) .attribute( IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, IdentityNamespace.TYPE_BUNDLE)) .content(new BundleArchiveBuilder() .symbolicName("b1") .exportPackage("a") .buildAsBytes()) .build()) .resource(new TestRepositoryContent.Builder() .capability(new TestCapability.Builder() .namespace(IdentityNamespace.IDENTITY_NAMESPACE) .attribute( IdentityNamespace.IDENTITY_NAMESPACE, "b2") .attribute( IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, Version.emptyVersion) .attribute( IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, IdentityNamespace.TYPE_BUNDLE)) .content(new BundleArchiveBuilder() .symbolicName("b2") .importPackage("a") .buildAsBytes()) .build()) .build(), null)); Subsystem root = getRootSubsystem(); Subsystem s1 = installSubsystem( root, "s1", new SubsystemArchiveBuilder() .symbolicName("s1") .type(SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()) .build(), false ); uninstallableSubsystems.add(s1); startSubsystem(s1, false); stoppableSubsystems.add(s1); Subsystem f2 = installSubsystem( s1, "f2", new SubsystemArchiveBuilder() .symbolicName("f2") .type(SubsystemConstants.SUBSYSTEM_TYPE_FEATURE) .content("b2") .build(), false ); uninstallableSubsystems.add(f2); assertChild(s1, "f2", null, SubsystemConstants.SUBSYSTEM_TYPE_FEATURE); assertConstituent(f2, "b2"); Subsystem f1 = installSubsystem( s1, "f1", new SubsystemArchiveBuilder() .symbolicName("f1") .type(SubsystemConstants.SUBSYSTEM_TYPE_FEATURE) .content("b1") .build(), false ); uninstallableSubsystems.add(f1); assertChild(s1, "f1", null, SubsystemConstants.SUBSYSTEM_TYPE_FEATURE); assertConstituent(f1, "b1"); assertNotConstituent(root, "b1"); } /* * (21) Install a scoped subsystem, S1, with * apache-aries-provision-dependencies:=resolve. Install two features, F1 and * F2, independently as children of S1. F1 has bundle B1 and B2 as content. * F2 has bundle B2 and B3 as content. B2 is shared content. B1 has a * dependency on bundle B4, B2 has a dependency on bundle B5. B3 has a * dependency on bundle B6. Start F1. Dependency bundles B4 and B5 should be * provisioned but not B6. */ @Test public void test21() throws Exception { serviceRegistrations.add(bundleContext.registerService( Repository.class, new TestRepository.Builder() .resource(new TestRepositoryContent.Builder() .capability(new TestCapability.Builder() .namespace(IdentityNamespace.IDENTITY_NAMESPACE) .attribute( IdentityNamespace.IDENTITY_NAMESPACE, "b1") .attribute( IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, Version.emptyVersion) .attribute( IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, IdentityNamespace.TYPE_BUNDLE)) .requirement(new TestRequirement.Builder() .namespace(PackageNamespace.PACKAGE_NAMESPACE) .directive( PackageNamespace.REQUIREMENT_FILTER_DIRECTIVE, "(osgi.wiring.package=b4)")) .content(new BundleArchiveBuilder() .symbolicName("b1") .importPackage("b4") .buildAsBytes()) .build()) .resource(new TestRepositoryContent.Builder() .capability(new TestCapability.Builder() .namespace(IdentityNamespace.IDENTITY_NAMESPACE) .attribute( IdentityNamespace.IDENTITY_NAMESPACE, "b2") .attribute( IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, Version.emptyVersion) .attribute( IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, IdentityNamespace.TYPE_BUNDLE)) .requirement(new TestRequirement.Builder() .namespace(PackageNamespace.PACKAGE_NAMESPACE) .directive( PackageNamespace.REQUIREMENT_FILTER_DIRECTIVE, "(osgi.wiring.package=b5)")) .content(new BundleArchiveBuilder() .symbolicName("b2") .importPackage("b5") .buildAsBytes()) .build()) .resource(new TestRepositoryContent.Builder() .capability(new TestCapability.Builder() .namespace(IdentityNamespace.IDENTITY_NAMESPACE) .attribute( IdentityNamespace.IDENTITY_NAMESPACE, "b3") .attribute( IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, Version.emptyVersion) .attribute( IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, IdentityNamespace.TYPE_BUNDLE)) .requirement(new TestRequirement.Builder() .namespace(PackageNamespace.PACKAGE_NAMESPACE) .directive( PackageNamespace.REQUIREMENT_FILTER_DIRECTIVE, "(osgi.wiring.package=b6)")) .content(new BundleArchiveBuilder() .symbolicName("b3") .importPackage("b6") .buildAsBytes()) .build()) .resource(new TestRepositoryContent.Builder() .capability(new TestCapability.Builder() .namespace(IdentityNamespace.IDENTITY_NAMESPACE) .attribute( IdentityNamespace.IDENTITY_NAMESPACE, "b4") .attribute( IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, Version.emptyVersion) .attribute( IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, IdentityNamespace.TYPE_BUNDLE)) .capability(new TestCapability.Builder() .namespace(PackageNamespace.PACKAGE_NAMESPACE) .attribute( PackageNamespace.PACKAGE_NAMESPACE, "b4")) .content(new BundleArchiveBuilder() .symbolicName("b4") .exportPackage("b4") .buildAsBytes()) .build()) .resource(new TestRepositoryContent.Builder() .capability(new TestCapability.Builder() .namespace(IdentityNamespace.IDENTITY_NAMESPACE) .attribute( IdentityNamespace.IDENTITY_NAMESPACE, "b5") .attribute( IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, Version.emptyVersion) .attribute( IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, IdentityNamespace.TYPE_BUNDLE)) .capability(new TestCapability.Builder() .namespace(PackageNamespace.PACKAGE_NAMESPACE) .attribute( PackageNamespace.PACKAGE_NAMESPACE, "b5")) .content(new BundleArchiveBuilder() .symbolicName("b5") .exportPackage("b5") .buildAsBytes()) .build()) .resource(new TestRepositoryContent.Builder() .capability(new TestCapability.Builder() .namespace(IdentityNamespace.IDENTITY_NAMESPACE) .attribute( IdentityNamespace.IDENTITY_NAMESPACE, "b6") .attribute( IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, Version.emptyVersion) .attribute( IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, IdentityNamespace.TYPE_BUNDLE)) .capability(new TestCapability.Builder() .namespace(PackageNamespace.PACKAGE_NAMESPACE) .attribute( PackageNamespace.PACKAGE_NAMESPACE, "b6")) .content(new BundleArchiveBuilder() .symbolicName("b6") .exportPackage("b6") .buildAsBytes()) .build()) .build(), null)); Subsystem root = getRootSubsystem(); Subsystem s1 = installSubsystem( root, "s1", new SubsystemArchiveBuilder() .symbolicName("s1") .type(SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString() + ';' + SubsystemConstants.PROVISION_POLICY_DIRECTIVE + ":=" + SubsystemConstants.PROVISION_POLICY_ACCEPT_DEPENDENCIES) .build(), false ); uninstallableSubsystems.add(s1); startSubsystem(s1, false); stoppableSubsystems.add(s1); Subsystem f2 = installSubsystem( s1, "f2", new SubsystemArchiveBuilder() .symbolicName("f2") .type(SubsystemConstants.SUBSYSTEM_TYPE_FEATURE) .content("b2,b3") .build(), false ); uninstallableSubsystems.add(f2); assertChild(s1, "f2", null, SubsystemConstants.SUBSYSTEM_TYPE_FEATURE); assertConstituent(s1, "f2", null, SubsystemConstants.SUBSYSTEM_TYPE_FEATURE); assertConstituent(f2, "b2"); assertConstituent(f2, "b3"); Subsystem f1 = installSubsystem( s1, "f1", new SubsystemArchiveBuilder() .symbolicName("f1") .type(SubsystemConstants.SUBSYSTEM_TYPE_FEATURE) .content("b1,b2") .build(), false ); uninstallableSubsystems.add(f1); assertChild(s1, "f1", null, SubsystemConstants.SUBSYSTEM_TYPE_FEATURE); assertConstituent(s1, "f1", null, SubsystemConstants.SUBSYSTEM_TYPE_FEATURE); assertConstituent(f1, "b1"); assertConstituent(f1, "b2"); startSubsystem(f1, false); stoppableSubsystems.add(f1); assertState(EnumSet.of(State.RESOLVED, State.ACTIVE), f2); assertConstituent(s1, "b4"); assertConstituent(s1, "b5"); assertConstituent(s1, "b6"); } @Test public void testFullLifeCycle() throws Exception { Subsystem root = getRootSubsystem(); Subsystem subsystem = installSubsystem(root, APPLICATION_EMPTY, applicationEmpty(), false); startSubsystem(subsystem, false); stopSubsystem(subsystem); uninstallSubsystem(subsystem); } @Test public void testImplicitlyInstalledChildOverridesProvisionDependencies() throws Exception { Subsystem root = getRootSubsystem(); subsystemEvents.clear(); try { Subsystem subsystem = root.install( "parent", new SubsystemArchiveBuilder() .symbolicName("parent") .type(SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.INSTALL.toString()) .subsystem( "child", new SubsystemArchiveBuilder() .symbolicName("child") .type(SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()) .build()) .build()); uninstallSubsystemSilently(subsystem); fail("Subsystem should not have installed"); } catch (SubsystemException e) { e.printStackTrace(); } } @Test public void testInstall() throws Exception { Subsystem root = getRootSubsystem(); try { Subsystem subsystem = installSubsystem(root, APPLICATION_EMPTY, applicationEmpty(), false); uninstallSubsystemSilently(subsystem); } catch (Exception e) { e.printStackTrace(); fail("Subsystem should have installed"); } } @Test public void testInstallChildIntoInstallingParent() throws Exception { Subsystem root = getRootSubsystem(); Subsystem subsystem = installSubsystem(root, APPLICATION_DEPENDENCY_IN_ARCHIVE, applicationDependencyInArchive(), false); try { assertState(State.INSTALLING, subsystem); installSubsystem(subsystem, APPLICATION_A, applicationA(), false); fail("Subsystem should not have installed"); } catch (SubsystemException e) { e.printStackTrace(); } finally { uninstallSubsystemSilently(subsystem); } } @Test public void testStart() throws Exception { Subsystem root = getRootSubsystem(); Subsystem subsystem = installSubsystem(root, APPLICATION_EMPTY, applicationEmpty(), false); try { startSubsystem(subsystem, false); stopSubsystemSilently(subsystem); } catch (Exception e) { e.printStackTrace(); fail("Subsystem should have started"); } finally { uninstallSubsystemSilently(subsystem); } } @Test public void testStop() throws Exception { Subsystem root = getRootSubsystem(); Subsystem subsystem = installSubsystem(root, APPLICATION_EMPTY, applicationEmpty(), false); try { startSubsystem(subsystem, false); try { stopSubsystem(subsystem); } catch (Exception e) { e.printStackTrace(); fail("Subsystem should have stopped"); } } finally { uninstallSubsystemSilently(subsystem); } } @Test public void testUninstall() throws Exception { Subsystem root = getRootSubsystem(); Subsystem subsystem = installSubsystem(root, APPLICATION_EMPTY, applicationEmpty(), false); try { uninstallSubsystem(subsystem); } catch (Exception e) { e.printStackTrace(); fail("Subsystem should have uninstalled"); } } private InputStream applicationA() throws Exception { Manifest manifest = new Manifest(); Attributes attributes = manifest.getMainAttributes(); attributes.putValue(Attributes.Name.MANIFEST_VERSION.toString(), "1.0"); attributes.putValue(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, APPLICATION_A); attributes.putValue(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()); attributes.putValue(SubsystemConstants.SUBSYSTEM_CONTENT, BUNDLE_A + ',' + BUNDLE_C); ByteArrayOutputStream baos = new ByteArrayOutputStream(); manifest.write(baos); baos.close(); return TinyBundles .bundle() .add(SUBSYSTEM_MANIFEST_FILE, new ByteArrayInputStream(baos.toByteArray())) .add(BUNDLE_A + JAR_EXTENSION, bundleA()) .add(BUNDLE_B + JAR_EXTENSION, bundleB()) .add(BUNDLE_C + JAR_EXTENSION, bundleC()) .add(BUNDLE_D + JAR_EXTENSION, bundleD()) .build(); } private InputStream applicationB() throws Exception { Manifest manifest = new Manifest(); Attributes attributes = manifest.getMainAttributes(); attributes.putValue(Attributes.Name.MANIFEST_VERSION.toString(), "1.0"); attributes.putValue(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, APPLICATION_B); attributes.putValue(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()); attributes.putValue(SubsystemConstants.SUBSYSTEM_CONTENT, BUNDLE_A + ',' + APPLICATION_A + ";type=osgi.subsystem.application"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); manifest.write(baos); baos.close(); return TinyBundles .bundle() .add(SUBSYSTEM_MANIFEST_FILE, new ByteArrayInputStream(baos.toByteArray())) .add(BUNDLE_A + JAR_EXTENSION, bundleA()) .add(BUNDLE_B + JAR_EXTENSION, bundleB()) .add(APPLICATION_A + ESA_EXTENSION, applicationA()) .build(); } private InputStream applicationDependencyInArchive() throws Exception { Manifest manifest = new Manifest(); Attributes attributes = manifest.getMainAttributes(); attributes.putValue(Attributes.Name.MANIFEST_VERSION.toString(), "1.0"); attributes.putValue(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, APPLICATION_DEPENDENCY_IN_ARCHIVE); attributes.putValue(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()); attributes.putValue(SubsystemConstants.SUBSYSTEM_CONTENT, BUNDLE_A); ByteArrayOutputStream baos = new ByteArrayOutputStream(); manifest.write(baos); baos.close(); return TinyBundles .bundle() .add(SUBSYSTEM_MANIFEST_FILE, new ByteArrayInputStream(baos.toByteArray())) .add(BUNDLE_A + JAR_EXTENSION, bundleA()) .add(BUNDLE_B + JAR_EXTENSION, bundleB()) .build(); } private InputStream applicationEmpty() throws Exception { Manifest manifest = new Manifest(); Attributes attributes = manifest.getMainAttributes(); attributes.putValue(Attributes.Name.MANIFEST_VERSION.toString(), MANIFEST_VERSION); attributes.putValue(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, APPLICATION_EMPTY); attributes.putValue(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); manifest.write(baos); baos.close(); return TinyBundles .bundle() .add(SUBSYSTEM_MANIFEST_FILE, new ByteArrayInputStream(baos.toByteArray())) .build(); } private InputStream applicationInstallFailed() throws Exception { Manifest manifest = new Manifest(); Attributes attributes = manifest.getMainAttributes(); attributes.putValue(Attributes.Name.MANIFEST_VERSION.toString(), MANIFEST_VERSION); attributes.putValue(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, APPLICATION_INSTALL_FAILED); attributes.putValue(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); manifest.write(baos); baos.close(); return TinyBundles .bundle() .add(SUBSYSTEM_MANIFEST_FILE, new ByteArrayInputStream(baos.toByteArray())) .add(BUNDLE_INVALID_MANIFEST + JAR_EXTENSION, bundleInvalidManifest()) .build(); } private InputStream applicationInvalidProvisionDependencies() throws Exception { Manifest manifest = new Manifest(); Attributes attributes = manifest.getMainAttributes(); attributes.putValue(Attributes.Name.MANIFEST_VERSION.toString(), "1.0"); attributes.putValue(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, APPLICATION_INVALID_PROVISION_DEPENDENCIES); attributes.putValue(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.NAME + ":=foo"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); manifest.write(baos); baos.close(); return TinyBundles .bundle() .add(SUBSYSTEM_MANIFEST_FILE, new ByteArrayInputStream(baos.toByteArray())) .build(); } private InputStream applicationMissingDependency() throws Exception { Manifest manifest = new Manifest(); Attributes attributes = manifest.getMainAttributes(); attributes.putValue(Attributes.Name.MANIFEST_VERSION.toString(), "1.0"); attributes.putValue(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, APPLICATION_MISSING_DEPENDENCY); attributes.putValue(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()); attributes.putValue(SubsystemConstants.SUBSYSTEM_CONTENT, BUNDLE_A); ByteArrayOutputStream baos = new ByteArrayOutputStream(); manifest.write(baos); baos.close(); return TinyBundles .bundle() .add(SUBSYSTEM_MANIFEST_FILE, new ByteArrayInputStream(baos.toByteArray())) .add(BUNDLE_A + JAR_EXTENSION, bundleA()) .build(); } private InputStream applicationProvisionDependenciesInstall() throws Exception { Manifest manifest = new Manifest(); Attributes attributes = manifest.getMainAttributes(); attributes.putValue(Attributes.Name.MANIFEST_VERSION.toString(), "1.0"); attributes.putValue(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, APPLICATION_PROVISION_DEPENDENCIES_INSTALL); attributes.putValue(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.INSTALL.toString()); attributes.putValue(SubsystemConstants.SUBSYSTEM_CONTENT, BUNDLE_A); ByteArrayOutputStream baos = new ByteArrayOutputStream(); manifest.write(baos); baos.close(); return TinyBundles .bundle() .add(SUBSYSTEM_MANIFEST_FILE, new ByteArrayInputStream(baos.toByteArray())) .add(BUNDLE_A + JAR_EXTENSION, bundleA()) .add(BUNDLE_B + JAR_EXTENSION, bundleB()) .build(); } private InputStream applicationStartFailure() throws Exception { Manifest manifest = new Manifest(); Attributes attributes = manifest.getMainAttributes(); attributes.putValue(Attributes.Name.MANIFEST_VERSION.toString(), "1.0"); attributes.putValue(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, APPLICATION_START_FAILURE); attributes.putValue(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()); attributes.putValue(SubsystemConstants.SUBSYSTEM_CONTENT, BUNDLE_START_FAILURE); ByteArrayOutputStream baos = new ByteArrayOutputStream(); manifest.write(baos); baos.close(); return TinyBundles .bundle() .add(SUBSYSTEM_MANIFEST_FILE, new ByteArrayInputStream(baos.toByteArray())) .add(BUNDLE_START_FAILURE + JAR_EXTENSION, bundleStartFailure()) .build(); } private void assertReferences(Class<?> clazz, String filter, int expected) throws Exception { ServiceReference<?>[] references = bundleContext.getAllServiceReferences(clazz.getName(), filter); if (expected < 1) { assertNull("References exist", references); } else { assertNotNull("No references", references); assertEquals("No references or more than one", expected, references.length); } } private InputStream bundleA() { return TinyBundles .bundle() .set(Constants.BUNDLE_SYMBOLICNAME, BUNDLE_A) .set(Constants.EXPORT_PACKAGE, PACKAGE_A) .set(Constants.IMPORT_PACKAGE, PACKAGE_B) .build(); } private InputStream bundleB() { return TinyBundles .bundle() .set(Constants.BUNDLE_SYMBOLICNAME, BUNDLE_B) .set(Constants.EXPORT_PACKAGE, PACKAGE_B) .build(); } private InputStream bundleC() { return TinyBundles .bundle() .set(Constants.BUNDLE_SYMBOLICNAME, BUNDLE_C) .set(Constants.EXPORT_PACKAGE, PACKAGE_C) .set(Constants.IMPORT_PACKAGE, PACKAGE_B) .set(Constants.IMPORT_PACKAGE, PACKAGE_D) .build(); } private InputStream bundleD() { return TinyBundles .bundle() .set(Constants.BUNDLE_SYMBOLICNAME, BUNDLE_D) .set(Constants.EXPORT_PACKAGE, PACKAGE_D) .build(); } private InputStream bundleInvalidManifest() { return TinyBundles .bundle() .set(Constants.BUNDLE_SYMBOLICNAME, BUNDLE_INVALID_MANIFEST) .set(Constants.PROVIDE_CAPABILITY, "osgi.ee;osgi.ee=J2SE-1.4") .build(); } private InputStream bundleStartFailure() { return TinyBundles .bundle() .set(Constants.BUNDLE_SYMBOLICNAME, BUNDLE_START_FAILURE) .set(Constants.BUNDLE_ACTIVATOR, BundleStartFailureActivator.class.getName()) .add(BundleStartFailureActivator.class, InnerClassStrategy.NONE) .build(); } private InputStream featureProvisionDependenciesResolve() throws Exception { Manifest manifest = new Manifest(); Attributes attributes = manifest.getMainAttributes(); attributes.putValue(Attributes.Name.MANIFEST_VERSION.toString(), "1.0"); attributes.putValue(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, FEATURE_PROVISION_DEPENDENCIES_RESOLVE); attributes.putValue(SubsystemConstants.SUBSYSTEM_TYPE, SubsystemConstants.SUBSYSTEM_TYPE_FEATURE + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); manifest.write(baos); baos.close(); return TinyBundles .bundle() .add(SUBSYSTEM_MANIFEST_FILE, new ByteArrayInputStream(baos.toByteArray())) .build(); } public static interface TestService {} public static class TestServiceImpl implements TestService {} public static class TestServiceClientActivator implements BundleActivator { @Override public void start(BundleContext context) throws Exception { ServiceReference<TestService> ref = null; for (int i = 0; i < 80; i++) { // 20 seconds with 250ms sleep. ref = context.getServiceReference(TestService.class); if (ref == null) { Thread.sleep(250); continue; } break; } try { TestService service = context.getService(ref); service.getClass(); } finally { context.ungetService(ref); } } @Override public void stop(BundleContext context) throws Exception { } } public static class TestServiceImplActivator implements BundleActivator { private ServiceRegistration<TestService> reg; @Override public void start(BundleContext context) throws Exception { reg = context.registerService( TestService.class, new TestServiceImpl(), null); } @Override public void stop(BundleContext context) throws Exception { reg.unregister(); } } private static class BundleStartFailureActivator implements BundleActivator { @Override public void start(BundleContext context) throws Exception { throw new IllegalStateException(); } @Override public void stop(BundleContext context) throws Exception { // Nothing. } } @Test public void testInterleavingContentDependencies() throws Exception { Subsystem root = getRootSubsystem(); Subsystem c1 = installSubsystem( root, "c1", new SubsystemArchiveBuilder() .symbolicName("c1") .type(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()) .content("c1b1;version=\"[0,0]\"") .exportPackage("c1b1") .importPackage("c2b1") .bundle( "c1b1", new BundleArchiveBuilder() .symbolicName("c1b1") .exportPackage("c1b1") .importPackage("c2b1") .build()) .build(), false ); uninstallableSubsystems.add(c1); Subsystem c2 = installSubsystem( root, "c2", new SubsystemArchiveBuilder() .symbolicName("c2") .type(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()) .content("c2b1;version=\"[0,0]\"") .exportPackage("c2b1") .importPackage("c1b1") .bundle( "c2b1", new BundleArchiveBuilder() .symbolicName("c2b1") .exportPackage("c2b1") .importPackage("c1b1") .build()) .build(), false ); uninstallableSubsystems.add(c2); startSubsystem(c1, false); stoppableSubsystems.add(c1); assertState(EnumSet.of(State.RESOLVED, State.ACTIVE), c2); stoppableSubsystems.add(c2); } @Test public void testRestart2() throws Exception { Subsystem root = getRootSubsystem(); Subsystem c1 = installSubsystem( root, "c1", new SubsystemArchiveBuilder() .symbolicName("c1") .type(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()) .content("c1b1;version=\"[0,0]\"") .exportPackage("c1b1") .importPackage("c2b1") .bundle( "c1b1", new BundleArchiveBuilder() .symbolicName("c1b1") .exportPackage("c1b1") .importPackage("c2b1") .build()) .build(), false ); uninstallableSubsystems.add(c1); Subsystem c2 = installSubsystem( root, "c2", new SubsystemArchiveBuilder() .symbolicName("c2") .type(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()) .content("c2b1;version=\"[0,0]\"") .exportPackage("c2b1") .importPackage("c1b1") .bundle( "c2b1", new BundleArchiveBuilder() .symbolicName("c2b1") .exportPackage("c2b1") .importPackage("c1b1") .build()) .build(), false ); uninstallableSubsystems.add(c2); assertChild(root, "c1", null, SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE); assertChild(root, "c2", null, SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE); restartSubsystemsImplBundle(); root = getRootSubsystem(); c1 = getChild(root, "c1", null, SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE); assertNotNull("Missing child", c1); uninstallableSubsystems.add(c1); c2 = getChild(root, "c2", null, SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE); assertNotNull("Missing child", c2); uninstallableSubsystems.add(c2); startSubsystem(c1, false); stoppableSubsystems.add(c1); try { assertState(EnumSet.of(State.RESOLVED, State.ACTIVE), c2); } catch (AssertionError e) { System.out.println(c2.getState()); } } @Test public void testRestart() throws Exception { Subsystem root = getRootSubsystem(); Subsystem a1 = installSubsystem( root, "a1", new SubsystemArchiveBuilder() .symbolicName("a1") .type(SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()) .content("b1,c1;type=osgi.subsystem.composite") .bundle( "b1", new BundleArchiveBuilder() .symbolicName("b1") .importPackage("b2") .build()) .bundle( "b2", new BundleArchiveBuilder() .symbolicName("b2") .exportPackage("b2") .build()) .subsystem( "c1", new SubsystemArchiveBuilder() .symbolicName("c1") .type(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()) .content("b1;version=\"[0,0]\"") .importPackage("b2") .bundle( "b1", new BundleArchiveBuilder() .symbolicName("b1") .importPackage("b2") .build()) .build()) .build(), false); uninstallableSubsystems.add(a1); assertChild(root, "a1"); assertState(State.INSTALLING, a1); Subsystem c1 = getChild(a1, "c1", null, SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE); assertNotNull("Missing child", c1); assertState(State.INSTALLING, c1); restartSubsystemsImplBundle(); root = getRootSubsystem(); a1 = getChild(root, "a1"); assertNotNull("Missing child", a1); uninstallableSubsystems.add(a1); assertState(State.INSTALLING, a1); assertConstituent(a1, "b1"); assertNotConstituent(root, "b2"); c1 = getChild(a1, "c1", null, SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE); assertNotNull("Missing child", c1); uninstallableSubsystems.add(c1); assertConstituent(c1, "b1"); startSubsystem(c1, false); stoppableSubsystems.add(c1); assertState(State.INSTALLED, a1); stoppableSubsystems.add(a1); assertConstituent(root, "b2"); } @Test public void test4e3bCompliance() throws Exception { serviceRegistrations.add(bundleContext.registerService( Repository.class, new TestRepository.Builder() .resource(new TestRepositoryContent.Builder() .capability(new TestCapability.Builder() .namespace(IdentityNamespace.IDENTITY_NAMESPACE) .attribute( IdentityNamespace.IDENTITY_NAMESPACE, "a") .attribute( IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, Version.emptyVersion) .attribute( IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, IdentityNamespace.TYPE_BUNDLE)) .capability(new TestCapability.Builder() .namespace(PackageNamespace.PACKAGE_NAMESPACE) .attribute( PackageNamespace.PACKAGE_NAMESPACE, "x") .attribute( IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, Version.emptyVersion)) .capability(new TestCapability.Builder() .namespace(BundleNamespace.BUNDLE_NAMESPACE) .attribute( BundleNamespace.BUNDLE_NAMESPACE, "a") .attribute( BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE, Version.emptyVersion)) .content(new BundleArchiveBuilder() .symbolicName("a") .exportPackage("x") .buildAsBytes()) .build()) .resource(new TestRepositoryContent.Builder() .capability(new TestCapability.Builder() .namespace(IdentityNamespace.IDENTITY_NAMESPACE) .attribute( IdentityNamespace.IDENTITY_NAMESPACE, "b") .attribute( IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, Version.emptyVersion) .attribute( IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, IdentityNamespace.TYPE_BUNDLE)) .capability(new TestCapability.Builder() .namespace("y")) .content(new BundleArchiveBuilder() .symbolicName("b") .header("Provide-Capability", "y") .buildAsBytes()) .build()) .build(), null)); Subsystem root = getRootSubsystem(); try { Subsystem s1 = installSubsystem( root, "s1", new SubsystemArchiveBuilder() .symbolicName("s1") .type(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE) .subsystem( "s3", new SubsystemArchiveBuilder() .symbolicName("s3") .type(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE) .subsystem( "s2", new SubsystemArchiveBuilder() .symbolicName("s2") .type(SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION) .bundle( "c", new BundleArchiveBuilder() .symbolicName("c") .importPackage("x") .build()) .bundle( "d", new BundleArchiveBuilder() .symbolicName("d") .header("Require-Bundle", "a") .build()) .bundle( "e", new BundleArchiveBuilder() .symbolicName("e") .header("Require-Capability", "y") .build()) .build()) .build()) .build(), true); uninstallableSubsystems.add(s1); fail("Subsystem should not have installed"); } catch (SubsystemException e) { e.printStackTrace(); } } @Test public void testMatchingCapabilityInDisconnectedRegion() throws Exception { Subsystem root = getRootSubsystem(); BundleArchiveBuilder b1Builder = new BundleArchiveBuilder() .symbolicName("b1") .exportPackage("b1"); Bundle b1 = root.getBundleContext().installBundle("b1", b1Builder.build()); try { Subsystem a1 = installSubsystem( root, "a1", new SubsystemArchiveBuilder() .symbolicName("a1") .type(SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString() + ';' + SubsystemConstants.PROVISION_POLICY_DIRECTIVE + ":=" + SubsystemConstants.PROVISION_POLICY_ACCEPT_DEPENDENCIES) .build(), false ); uninstallableSubsystems.add(a1); startSubsystem(a1, false); stoppableSubsystems.add(a1); removeConnectionWithParent(a1); Subsystem a2 = installSubsystem( a1, "a2", new SubsystemArchiveBuilder() .symbolicName("a2") .type(SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION) .content("b2") .bundle( "b2", new BundleArchiveBuilder() .symbolicName("b2") .importPackage("b1") .build()) .bundle( "b1", b1Builder.build()) .build(), false ); uninstallableSubsystems.add(a2); assertState(State.INSTALLING, a2); assertNotConstituent(a1, "b1"); try { startSubsystem(a2, false); stoppableSubsystems.add(a2); assertConstituent(a1, "b1"); } catch (SubsystemException e) { e.printStackTrace(); fail("Subsystem should have started"); } } finally { uninstallSilently(b1); } } @Test public void testProvideCapabilityNamespaceOnly() throws Exception { Subsystem root = getRootSubsystem(); Subsystem c1 = installSubsystem( root, "c1", new SubsystemArchiveBuilder() .symbolicName("c1") .type(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE) .provideCapability("y") .build()); uninstallableSubsystems.add(c1); try { startSubsystem(c1); stoppableSubsystems.add(c1); } catch (SubsystemException e) { e.printStackTrace(); fail("Subsystem should have started"); } } @Test public void testComApiComImplAppClient() throws Exception { Subsystem root = getRootSubsystem(); final Subsystem shared = installSubsystem( root, "shared", new SubsystemArchiveBuilder() .symbolicName("shared") .type(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString() + ';' + SubsystemConstants.PROVISION_POLICY_DIRECTIVE + ":=" + SubsystemConstants.PROVISION_POLICY_ACCEPT_DEPENDENCIES) .importPackage("org.osgi.framework") .build(), false ); uninstallableSubsystems.add(shared); shared.start(); stoppableSubsystems.add(shared); @SuppressWarnings("unchecked") Callable<Subsystem>[] installCallables = new Callable[] { new Callable<Subsystem>() { @Override public Subsystem call() throws Exception { Subsystem result = installSubsystem( shared, "client", new SubsystemArchiveBuilder() .symbolicName("client") .type(SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION) .bundle( "client", new BundleArchiveBuilder() .symbolicName("client") .importPackage("org.apache.aries.subsystem.itests.defect") .requireCapability("osgi.service;filter:=\"(objectClass=" + TestService.class.getName() + ")\";effective:=active") .build()) .build(), false); uninstallableSubsystems.add(result); return result; } }, new Callable<Subsystem>() { @Override public Subsystem call() throws Exception { Subsystem result = installSubsystem( shared, "impl", new SubsystemArchiveBuilder() .symbolicName("impl") .type(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE) .content("impl;version=\"[0,0]\"") .provideCapability("osgi.service;objectClass:List<String>=\"" + TestService.class.getName() + "\"") .importPackage("org.osgi.framework") .requireBundle("api") .bundle( "impl", new BundleArchiveBuilder() .symbolicName("impl") .provideCapability("osgi.service;objectClass:List<String>=\"" + TestService.class.getName() + "\"") .importPackage("org.osgi.framework") .requireBundle("api") .clazz(TestServiceImpl.class) .activator(TestServiceImplActivator.class) .build()) .build(), false); uninstallableSubsystems.add(result); return result; } }, new Callable<Subsystem>() { @Override public Subsystem call() throws Exception { Subsystem result = installSubsystem( shared, "api", new SubsystemArchiveBuilder() .symbolicName("api") .type(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE) .content("api;version=\"[0,0]\"") .exportPackage("org.apache.aries.subsystem.itests.defect") .provideCapability("osgi.wiring.bundle;osgi.wiring.bundle=api;bundle-version=0") .bundle( "api", new BundleArchiveBuilder() .symbolicName("api") .exportPackage("org.apache.aries.subsystem.itests.defect") .clazz(TestService.class) .build()) .build(), false); uninstallableSubsystems.add(result); return result; } } }; ExecutorService executor = Executors.newFixedThreadPool(3); List<Future<Subsystem>> installFutures = executor.invokeAll(Arrays.asList(installCallables)); final Subsystem a1 = installFutures.get(0).get(); final Subsystem c1 = installFutures.get(1).get(); final Subsystem c2 = installFutures.get(2).get(); @SuppressWarnings("unchecked") Callable<Void>[] startCallables = new Callable[] { new Callable<Void>() { @Override public Void call() throws Exception { a1.start(); stoppableSubsystems.add(a1); assertEvent(a1, State.INSTALLED, subsystemEvents.poll(a1.getSubsystemId(), 5000)); assertEvent(a1, State.RESOLVING, subsystemEvents.poll(a1.getSubsystemId(), 5000)); assertEvent(a1, State.RESOLVED, subsystemEvents.poll(a1.getSubsystemId(), 5000)); assertEvent(a1, State.STARTING, subsystemEvents.poll(a1.getSubsystemId(), 5000)); assertEvent(a1, State.ACTIVE, subsystemEvents.poll(a1.getSubsystemId(), 5000)); return null; } }, new Callable<Void>() { @Override public Void call() throws Exception { c1.start(); stoppableSubsystems.add(c1); assertEvent(c1, State.INSTALLED, subsystemEvents.poll(c1.getSubsystemId(), 5000)); assertEvent(c1, State.RESOLVING, subsystemEvents.poll(c1.getSubsystemId(), 5000)); assertEvent(c1, State.RESOLVED, subsystemEvents.poll(c1.getSubsystemId(), 5000)); assertEvent(c1, State.STARTING, subsystemEvents.poll(c1.getSubsystemId(), 5000)); assertEvent(c1, State.ACTIVE, subsystemEvents.poll(c1.getSubsystemId(), 5000)); return null; } }, new Callable<Void>() { @Override public Void call() throws Exception { c2.start(); stoppableSubsystems.add(c2); assertEvent(c2, State.INSTALLED, subsystemEvents.poll(c2.getSubsystemId(), 5000)); assertEvent(c2, State.RESOLVING, subsystemEvents.poll(c2.getSubsystemId(), 5000)); assertEvent(c2, State.RESOLVED, subsystemEvents.poll(c2.getSubsystemId(), 5000)); assertEvent(c2, State.STARTING, subsystemEvents.poll(c2.getSubsystemId(), 5000)); assertEvent(c2, State.ACTIVE, subsystemEvents.poll(c2.getSubsystemId(), 5000)); return null; } } }; List<Future<Void>> startFutures = executor.invokeAll(Arrays.asList(startCallables)); startFutures.get(0).get(); startFutures.get(1).get(); startFutures.get(2).get(); } @Test public void testComApiComImplComClient() throws Exception { Subsystem root = getRootSubsystem(); final Subsystem shared = installSubsystem( root, "shared", new SubsystemArchiveBuilder() .symbolicName("shared") .type(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString() + ';' + SubsystemConstants.PROVISION_POLICY_DIRECTIVE + ":=" + SubsystemConstants.PROVISION_POLICY_ACCEPT_DEPENDENCIES) .importPackage("org.osgi.framework") .build(), false ); uninstallableSubsystems.add(shared); shared.start(); stoppableSubsystems.add(shared); @SuppressWarnings("unchecked") Callable<Subsystem>[] installCallables = new Callable[] { new Callable<Subsystem>() { @Override public Subsystem call() throws Exception { Subsystem result = installSubsystem( shared, "client", new SubsystemArchiveBuilder() .symbolicName("client") .type(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE) .content("client;version=\"[0,0]\"") .importPackage("org.osgi.framework") .requireCapability("osgi.service;filter:=\"(objectClass=" + TestService.class.getName() + ")\";effective:=active") .importService(TestService.class.getName()) .requireBundle("api,impl") .bundle( "client", new BundleArchiveBuilder() .symbolicName("client") .importPackage("org.osgi.framework") .requireCapability("osgi.service;filter:=\"(objectClass=" + TestService.class.getName() + ")\";effective:=active") .requireBundle("api,impl") .activator(TestServiceClientActivator.class) .build()) .build(), false); return result; } }, new Callable<Subsystem>() { @Override public Subsystem call() throws Exception { Subsystem result = installSubsystem( shared, "impl", new SubsystemArchiveBuilder() .symbolicName("impl") .type(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE) .content("impl;version=\"[0,0]\"") .provideCapability("osgi.service;objectClass:List<String>=\"" + TestService.class.getName() + "\"") .exportService(TestService.class.getName()) .importPackage("org.osgi.framework") .requireBundle("api") .provideCapability("osgi.wiring.bundle;osgi.wiring.bundle=impl;bundle-version=0") .bundle( "impl", new BundleArchiveBuilder() .symbolicName("impl") .provideCapability("osgi.service;objectClass:List<String>=\"" + TestService.class.getName() + "\"") .importPackage("org.osgi.framework") .requireBundle("api") .clazz(TestServiceImpl.class) .activator(TestServiceImplActivator.class) .build()) .build(), false); return result; } }, new Callable<Subsystem>() { @Override public Subsystem call() throws Exception { Subsystem result = installSubsystem( shared, "api", new SubsystemArchiveBuilder() .symbolicName("api") .type(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE) .content("api;version=\"[0,0]\"") .exportPackage("org.apache.aries.subsystem.itests.defect") .provideCapability("osgi.wiring.bundle;osgi.wiring.bundle=api;bundle-version=0") .bundle( "api", new BundleArchiveBuilder() .symbolicName("api") .exportPackage("org.apache.aries.subsystem.itests.defect") .clazz(TestService.class) .build()) .build(), false); return result; } } }; ExecutorService executor = Executors.newFixedThreadPool(3); List<Future<Subsystem>> installFutures = executor.invokeAll(Arrays.asList(installCallables)); final Subsystem client = installFutures.get(0).get(); final Subsystem impl = installFutures.get(1).get(); final Subsystem api = installFutures.get(2).get(); @SuppressWarnings("unchecked") Callable<Void>[] startCallables = new Callable[] { new Callable<Void>() { @Override public Void call() throws Exception { client.start(); assertEvent(client, State.INSTALLED, subsystemEvents.poll(client.getSubsystemId(), 5000)); assertEvent(client, State.RESOLVING, subsystemEvents.poll(client.getSubsystemId(), 5000)); assertEvent(client, State.RESOLVED, subsystemEvents.poll(client.getSubsystemId(), 5000)); assertEvent(client, State.STARTING, subsystemEvents.poll(client.getSubsystemId(), 5000)); assertEvent(client, State.ACTIVE, subsystemEvents.poll(client.getSubsystemId(), 5000)); return null; } }, new Callable<Void>() { @Override public Void call() throws Exception { impl.start(); assertEvent(impl, State.INSTALLED, subsystemEvents.poll(impl.getSubsystemId(), 5000)); assertEvent(impl, State.RESOLVING, subsystemEvents.poll(impl.getSubsystemId(), 5000)); assertEvent(impl, State.RESOLVED, subsystemEvents.poll(impl.getSubsystemId(), 5000)); assertEvent(impl, State.STARTING, subsystemEvents.poll(impl.getSubsystemId(), 5000)); assertEvent(impl, State.ACTIVE, subsystemEvents.poll(impl.getSubsystemId(), 5000)); return null; } }, new Callable<Void>() { @Override public Void call() throws Exception { api.start(); assertEvent(api, State.INSTALLED, subsystemEvents.poll(api.getSubsystemId(), 5000)); assertEvent(api, State.RESOLVING, subsystemEvents.poll(api.getSubsystemId(), 5000)); assertEvent(api, State.RESOLVED, subsystemEvents.poll(api.getSubsystemId(), 5000)); assertEvent(api, State.STARTING, subsystemEvents.poll(api.getSubsystemId(), 5000)); assertEvent(api, State.ACTIVE, subsystemEvents.poll(api.getSubsystemId(), 5000)); return null; } } }; List<Future<Void>> startFutures = executor.invokeAll(Arrays.asList(startCallables)); startFutures.get(0).get(); startFutures.get(1).get(); startFutures.get(2).get(); } @Test public void testAutoInstallDependenciesComposite() throws Exception { Subsystem root = getRootSubsystem(); Subsystem b = installSubsystem( root, "b", new SubsystemArchiveBuilder() .symbolicName("b") .type(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString()) .content("a;version=\"[0,0]\"") .exportPackage("a") .importPackage("b") .bundle( "a", new BundleArchiveBuilder() .symbolicName("a") .importPackage("b") .exportPackage("a") .build()) .bundle( "b", new BundleArchiveBuilder() .symbolicName("b") .exportPackage("b") .build()) .build(), false ); uninstallableSubsystems.add(b); try { Subsystem a = installSubsystem( root, "a", new SubsystemArchiveBuilder() .symbolicName("a") .type(SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION) .bundle( "a", new BundleArchiveBuilder() .symbolicName("a") .importPackage("a") .build()) .build(), true ); uninstallableSubsystems.add(a); assertState(EnumSet.of(State.INSTALLED, State.RESOLVED), b); } catch (Exception e) { e.printStackTrace(); fail("Subsystem should have installed"); } } @Test public void testAutoInstallDependenciesFeature() throws Exception { Subsystem root = getRootSubsystem(); Subsystem shared = installSubsystem( root, "shared", new SubsystemArchiveBuilder() .symbolicName("shared") .type(SubsystemConstants.SUBSYSTEM_TYPE_COMPOSITE + ';' + AriesProvisionDependenciesDirective.RESOLVE.toString() + ';' + SubsystemConstants.PROVISION_POLICY_DIRECTIVE + ":=" + SubsystemConstants.PROVISION_POLICY_ACCEPT_DEPENDENCIES) .build(), false ); uninstallableSubsystems.add(shared); startSubsystem(shared, false); Subsystem b = installSubsystem( shared, "b", new SubsystemArchiveBuilder() .symbolicName("b") .type(SubsystemConstants.SUBSYSTEM_TYPE_FEATURE) .content("a") .bundle( "a", new BundleArchiveBuilder() .symbolicName("a") .importPackage("b") .exportPackage("a") .build()) .bundle( "b", new BundleArchiveBuilder() .symbolicName("b") .exportPackage("b") .build()) .build(), false ); try { installSubsystem( shared, "a", new SubsystemArchiveBuilder() .symbolicName("a") .type(SubsystemConstants.SUBSYSTEM_TYPE_APPLICATION + ';' + AriesProvisionDependenciesDirective.INSTALL.toString()) .bundle( "a", new BundleArchiveBuilder() .symbolicName("a") .importPackage("a") .build()) .build(), true ); assertState(EnumSet.of(State.INSTALLED, State.RESOLVED), b); } catch (Exception e) { e.printStackTrace(); fail("Subsystem should have installed"); } } }