| /******************************************************************************* |
| * Copyright (c) 2008, 2010 VMware Inc. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * VMware Inc. - initial contribution |
| *******************************************************************************/ |
| |
| package org.eclipse.virgo.kernel.deployer.test; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertTrue; |
| |
| import java.io.File; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.io.Writer; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.eclipse.virgo.nano.deployer.api.core.DeploymentException; |
| import org.eclipse.virgo.nano.deployer.api.core.DeploymentIdentity; |
| import org.eclipse.virgo.kernel.model.Artifact; |
| import org.eclipse.virgo.kernel.model.ArtifactState; |
| import org.eclipse.virgo.kernel.model.RuntimeArtifactRepository; |
| import org.eclipse.equinox.region.Region; |
| import org.junit.After; |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.BundleException; |
| import org.osgi.framework.ServiceReference; |
| import org.osgi.framework.Version; |
| import org.osgi.service.packageadmin.ExportedPackage; |
| |
| |
| /** |
| * These tests cover parent and child plans in all combinations of scoped/unscoped and atomic/non-atomic. |
| * <p/> |
| * A bundle "global" exports the package "global". A bundle "parent" in the parent plans exports the package "parent" |
| * imports the bundle "global" with application import scope. A bundle "child" in the child plans exports the package |
| * "child". |
| * <p/> |
| * An inner class called {@link Model} encapsulates how the various combinations should work in terms of scoping and |
| * atomicity. |
| * <p/> |
| * When scoping occurs, the tests check the synthetic context bundle and the promotion of the "global" package when |
| * appropriate. The lifecycle dependence or independence is checked between the bundles "parent" and "child" and between |
| * the parent and child plans. |
| * |
| */ |
| @SuppressWarnings("deprecation") |
| public class NestedPlanIntegrationTests extends AbstractDeployerIntegrationTest { |
| |
| private static final String GLOBAL_PACKAGE = "global"; |
| |
| private static final String PARENT_PACKAGE_NAME = "parent"; |
| |
| private static final String CHILD_PACKAGE_NAME = "child"; |
| |
| private static final String SCOPE_SEPARATOR = "-"; |
| |
| private static final String SYNTHETIC_CONTEXT_BSN_SUFFIX = "-synthetic.context"; |
| |
| private static final String PLAN_TYPE = "plan"; |
| |
| private static final String BUNDLE_TYPE = "bundle"; |
| |
| private static final int WATCH_INTERVAL_MS = 1000; |
| |
| /* |
| * An artifact must be present in a watched repository directory for up to two watch intervals before it will be |
| * processed. Then it will take a while (a surprisingly long while on some operating systems) to be scheduled and |
| * complete processing. |
| */ |
| private static final int WATCH_WAIT_INTERVAL_MS = 2 * WATCH_INTERVAL_MS + 1000; |
| |
| private static final String TEST_RESOURCES_DIRECTORY = "src/test/resources/plan-deployment/"; |
| |
| private static final String GENERATED_PLAN_DIRECTORY = "build/watched/"; |
| |
| private static final String PLAN_EXTENSION = ".plan"; |
| |
| private static final String XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; |
| |
| private static final String NAMESPACES = " xmlns=\"http://www.eclipse.org/virgo/schema/plan\" \n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n xsi:schemaLocation=\" http://www.eclipse.org/virgo/schema/plan http://www.eclipse.org/virgo/schema/plan/eclipse-virgo-plan.xsd\""; |
| |
| private static final Version DEFAULT_VERSION = new Version("0"); |
| |
| private static TestArtifactInfo GLOBAL_BUNDLE_INFO = new TestArtifactInfo("bundle", GLOBAL_PACKAGE, DEFAULT_VERSION); |
| |
| private static TestArtifactInfo PARENT_BUNDLE_INFO = new TestArtifactInfo("bundle", PARENT_PACKAGE_NAME, DEFAULT_VERSION); |
| |
| private static TestArtifactInfo CHILD_BUNDLE_INFO = new TestArtifactInfo("bundle", CHILD_PACKAGE_NAME, DEFAULT_VERSION); |
| |
| static { |
| GLOBAL_BUNDLE_INFO.setFile(new File(TEST_RESOURCES_DIRECTORY + "global.jar")); |
| } |
| |
| private RuntimeArtifactRepository ram = null; |
| |
| private Region globalRegion; |
| |
| private static TestPlanArtifactInfo[] PARENTS; |
| |
| private DeploymentIdentity globalBundleDeploymentIdentity; |
| |
| @BeforeClass |
| public static void setUpClass() throws Exception { |
| File generatedPlanDirectory = new File(GENERATED_PLAN_DIRECTORY); |
| generatedPlanDirectory.mkdirs(); |
| |
| generatePlans(); |
| } |
| |
| @Before |
| public void setUp() throws Exception { |
| ServiceReference<RuntimeArtifactRepository> runtimeArtifactRepositoryServiceReference = context.getServiceReference(RuntimeArtifactRepository.class); |
| if (runtimeArtifactRepositoryServiceReference != null) { |
| this.ram = context.getService(runtimeArtifactRepositoryServiceReference); |
| } |
| |
| if(this.ram == null){ |
| throw new RuntimeException("Unable to locate the RuntimeArtifactRepository. Found " + runtimeArtifactRepositoryServiceReference); |
| } |
| |
| Collection<ServiceReference<Region>> regionServiceReferences = context.getServiceReferences(Region.class, "(org.eclipse.virgo.kernel.region.name=global)"); |
| if (regionServiceReferences != null && regionServiceReferences.size() == 1) { |
| this.globalRegion = context.getService(regionServiceReferences.iterator().next()); |
| } |
| |
| globalBundleDeploymentIdentity = deploy(GLOBAL_BUNDLE_INFO); |
| } |
| |
| @After |
| public void tearDown() throws Exception { |
| if (this.globalBundleDeploymentIdentity != null) { |
| this.deployer.undeploy(this.globalBundleDeploymentIdentity); |
| this.globalBundleDeploymentIdentity = null; |
| } |
| } |
| |
| @Test |
| public void testUnscopedNonatomicParentOfUnscopedNonatomicChild() throws IOException, DeploymentException, InterruptedException { |
| testParent("unscoped.nonatomic.parentOf.unscoped.nonatomic.child"); |
| } |
| |
| @Test |
| public void testUnscopedAtomicParentOfUnscopedNonatomicChild() throws IOException, DeploymentException, InterruptedException { |
| testParent("unscoped.atomic.parentOf.unscoped.nonatomic.child"); |
| } |
| |
| @Test |
| public void testScopedNonatomicParentOfUnscopedNonatomicChild() throws IOException, DeploymentException, InterruptedException { |
| testParent("scoped.nonatomic.parentOf.unscoped.nonatomic.child"); |
| } |
| |
| @Test |
| public void testScopedAtomicParentOfUnscopedNonatomicChild() throws IOException, DeploymentException, InterruptedException { |
| testParent("scoped.atomic.parentOf.unscoped.nonatomic.child"); |
| } |
| |
| @Test |
| public void testUnscopedNonatomicParentOfUnscopedAtomicChild() throws IOException, DeploymentException, InterruptedException { |
| testParent("unscoped.nonatomic.parentOf.unscoped.atomic.child"); |
| } |
| |
| @Test |
| public void testUnscopedAtomicParentOfUnscopedAtomicChild() throws IOException, DeploymentException, InterruptedException { |
| testParent("unscoped.atomic.parentOf.unscoped.atomic.child"); |
| } |
| |
| @Test |
| public void testScopedNonatomicParentOfUnscopedAtomicChild() throws IOException, DeploymentException, InterruptedException { |
| testParent("scoped.nonatomic.parentOf.unscoped.atomic.child"); |
| } |
| |
| @Test |
| public void testScopedAtomicParentOfUnscopedAtomicChild() throws IOException, DeploymentException, InterruptedException { |
| testParent("scoped.atomic.parentOf.unscoped.atomic.child"); |
| } |
| |
| @Test |
| public void testUnscopedNonatomicParentOfScopedNonatomicChild() throws IOException, DeploymentException, InterruptedException { |
| testParent("unscoped.nonatomic.parentOf.scoped.nonatomic.child"); |
| } |
| |
| @Test |
| public void testUnscopedAtomicParentOfScopedNonatomicChild() throws IOException, DeploymentException, InterruptedException { |
| testParent("unscoped.atomic.parentOf.scoped.nonatomic.child"); |
| } |
| |
| @Test |
| public void testScopedNonatomicParentOfScopedNonatomiChild() throws IOException, DeploymentException, InterruptedException { |
| testParent("scoped.nonatomic.parentOf.scoped.nonatomic.child"); |
| } |
| |
| @Test |
| public void testScopedAtomicParentOfScopedNonatomicChild() throws IOException, DeploymentException, InterruptedException { |
| testParent("scoped.atomic.parentOf.scoped.nonatomic.child"); |
| } |
| |
| @Test |
| public void testUnscopedNonatomicParentOfScopedAtomicChild() throws IOException, DeploymentException, InterruptedException { |
| testParent("unscoped.nonatomic.parentOf.scoped.atomic.child"); |
| } |
| |
| @Test |
| public void testUnscopedAtomicParentOfScopedAtomicChild() throws IOException, DeploymentException, InterruptedException { |
| testParent("unscoped.atomic.parentOf.scoped.atomic.child"); |
| } |
| |
| @Test |
| public void testScopedNonatomicParentOfScopedAtomicChild() throws IOException, DeploymentException, InterruptedException { |
| testParent("scoped.nonatomic.parentOf.scoped.atomic.child"); |
| } |
| |
| @Test |
| public void testScopedAtomicParentOfScopedAtomicChild() throws IOException, DeploymentException, InterruptedException { |
| testParent("scoped.atomic.parentOf.scoped.atomic.child"); |
| } |
| |
| /** |
| * @throws IOException |
| * @throws DeploymentException |
| * @throws InterruptedException |
| */ |
| private void testParent(String parentName) throws IOException, DeploymentException, InterruptedException { |
| for (int p = 0; p < PARENTS.length; p++) { |
| TestPlanArtifactInfo parent = PARENTS[p]; |
| if (parentName.equals(parent.getName())) { |
| testParent(parent); |
| } |
| } |
| } |
| |
| private void testParent(TestPlanArtifactInfo parent) { |
| Model model = new Model(parent); |
| |
| boolean expectDeployOk = model.shouldDeployOk(); |
| |
| try { |
| DeploymentIdentity parentId = deploy(parent); |
| |
| // Fail the test if the plan should not have deployed ok. |
| assertTrue(expectDeployOk); |
| |
| checkScoping(parent, model); |
| |
| checkAtomicity(parent, model); |
| |
| this.deployer.undeploy(parentId); |
| } catch (DeploymentException e) { |
| // Fail the test if the plan should have deployed ok. |
| assertFalse("The plan '" + parent.getName() + "' failed to deploy '" + e.getMessage() + "'", expectDeployOk); |
| } |
| } |
| |
| private static void generatePlans() throws IOException, InterruptedException { |
| // Generate the child plans |
| TestPlanArtifactInfo[] children = generateChildPlans(); |
| |
| // Wait for watched directory interval to pass. |
| Thread.sleep(WATCH_WAIT_INTERVAL_MS); |
| |
| PARENTS = generateParentPlans(children); |
| } |
| |
| private void checkScoping(TestPlanArtifactInfo parent, Model model) { |
| |
| if (model.shouldHaveScope()) { |
| checkSyntheticContextBundle(model); |
| checkImportPromotion(model); |
| checkPlanScoping(parent, model); |
| } else { |
| checkNoSyntheticContextBundle(); |
| checkNoImportPromotion(model); |
| } |
| } |
| |
| private void checkPlanScoping(TestPlanArtifactInfo parent, Model model) { |
| if (parent.isScoped()) { |
| Artifact parentPlan = getPlan(parent); |
| Set<Artifact> children = parentPlan.getDependents(); |
| for (Artifact child : children) { |
| if (PLAN_TYPE.equals(child.getType())) { |
| String childPlanName = child.getName(); |
| String unscopedChildPlanName = parent.getChildPlan().getName(); |
| String expectedChildPlanName = model.getScopeName() + SCOPE_SEPARATOR + unscopedChildPlanName; |
| assertEquals(expectedChildPlanName, childPlanName); |
| } |
| } |
| } |
| |
| } |
| |
| private void checkSyntheticContextBundle(Model model) { |
| Bundle syntheticContextBundle = getSyntheticContextBundle(model.getScopeName()); |
| assertNotNull(syntheticContextBundle); |
| |
| if (model.syntheticContextShouldIncludeParent()) { |
| assertTrue(contains(getBundlesImportingPackage(PARENT_PACKAGE_NAME), syntheticContextBundle)); |
| } |
| |
| if (model.syntheticContextShouldIncludeChild()) { |
| assertTrue(contains(getBundlesImportingPackage(CHILD_PACKAGE_NAME), syntheticContextBundle)); |
| } |
| } |
| |
| private static boolean contains(Bundle[] importingBundles, Bundle syntheticContextBundle) { |
| if (importingBundles != null) { |
| for (Bundle bundle : importingBundles) { |
| if (bundle == syntheticContextBundle) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| private Bundle[] getBundlesImportingPackage(String pkg) { |
| ExportedPackage[] exportedPackages = this.packageAdmin.getExportedPackages(pkg); |
| |
| // The tests should not export a package from multiple bundles at any point in time. |
| assertEquals("The Package '" + pkg + "' is exported from " + exportedPackages.length + " bundles.", 1, exportedPackages.length); |
| |
| ExportedPackage parentExportedPackage = exportedPackages[0]; |
| Bundle[] importingBundles = parentExportedPackage.getImportingBundles(); |
| return importingBundles; |
| } |
| |
| private void checkNoSyntheticContextBundle() { |
| Bundle[] bundles = this.framework.getBundleContext().getBundles(); |
| for (Bundle bundle : bundles) { |
| assertFalse(bundle.getSymbolicName().endsWith(SYNTHETIC_CONTEXT_BSN_SUFFIX)); |
| } |
| } |
| |
| private Bundle getSyntheticContextBundle(String scopeName) { |
| String bsn = scopeName + SYNTHETIC_CONTEXT_BSN_SUFFIX; |
| Bundle[] bundles = this.packageAdmin.getBundles(bsn, null); |
| assertTrue(bundles.length <= 1); |
| return bundles.length == 0 ? null : bundles[0]; |
| } |
| |
| private void checkImportPromotion(Model model) { |
| if (model.importShouldBePromoted()) { |
| assertTrue(globalImportHasBeenPromoted(model)); |
| } |
| } |
| |
| private void checkNoImportPromotion(Model model) { |
| assertFalse(globalImportHasBeenPromoted(model)); |
| } |
| |
| private boolean globalImportHasBeenPromoted(Model model) { |
| // The global import has been promoted if and only if the child bundle imports it. |
| Bundle childBundle = model.getChildBundle(); |
| Bundle[] bundlesImportingGlobalPackage = getBundlesImportingPackage(GLOBAL_PACKAGE); |
| return contains(bundlesImportingGlobalPackage, childBundle); |
| } |
| |
| private void checkAtomicity(TestPlanArtifactInfo parent, Model model) { |
| TestPlanArtifactInfo childPlan = parent.getChildPlan(); |
| |
| Artifact parentArtifact = getPlan(parent); |
| Artifact childArtifact; |
| |
| if (parent.isScoped()) { |
| childArtifact = getPlan(childPlan.getType(), model.getScopeName() + SCOPE_SEPARATOR + childPlan.getName(), childPlan.getVersion(), globalRegion); |
| } else { |
| childArtifact = getPlan(childPlan); |
| } |
| |
| if (parent.isAtomic() && childPlan.isAtomic()) { |
| checkParentAndChildBundleLifecyclesAreTied(model.getParentBundle(), model.getChildBundle(), parentArtifact, childArtifact); |
| } else { |
| checkParentAndChildBundleLifecyclesAreIndependent(parent.isAtomic(), model.getParentBundle(), model.getChildBundle(), parentArtifact, childArtifact); |
| } |
| |
| if (parent.isAtomic()) { |
| checkParentAndChildPlanLifecyclesAreTied(parentArtifact, childArtifact); |
| } else { |
| checkParentAndChildPlanLifecyclesAreIndependent(parentArtifact, childArtifact); |
| } |
| } |
| |
| private Artifact getPlan(TestPlanArtifactInfo plan) { |
| return getPlan(plan.getType(), plan.getName(), plan.getVersion(), globalRegion); |
| } |
| |
| private Artifact getPlan(String type, String name, Version version, Region region) { |
| Artifact planArtifact = this.ram.getArtifact(type, name, version, region); |
| assertNotNull(planArtifact); |
| return planArtifact; |
| } |
| |
| private void checkParentAndChildPlanLifecyclesAreTied(Artifact parentPlan, Artifact childPlan) { |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| |
| parentPlan.stop(); |
| assertEquals(ArtifactState.RESOLVED, parentPlan.getState()); |
| assertEquals(ArtifactState.RESOLVED, childPlan.getState()); |
| |
| parentPlan.start(); |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| |
| childPlan.stop(); |
| assertEquals(ArtifactState.RESOLVED, parentPlan.getState()); |
| assertEquals(ArtifactState.RESOLVED, childPlan.getState()); |
| |
| childPlan.start(); |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| } |
| |
| private void checkParentAndChildPlanLifecyclesAreIndependent(Artifact parentPlan, Artifact childPlan) { |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| |
| parentPlan.stop(); |
| assertEquals(ArtifactState.RESOLVED, parentPlan.getState()); |
| // Stopping the parent plan stops the child plan regardless of the parent's atomicity. |
| assertEquals(ArtifactState.RESOLVED, childPlan.getState()); |
| |
| parentPlan.start(); |
| waitUntilActive(parentPlan); |
| // Starting the parent plan stops the child plan regardless of the parent's atomicity. |
| waitUntilActive(childPlan); |
| |
| childPlan.stop(); |
| assertEquals(ArtifactState.ACTIVE, parentPlan.getState()); |
| assertEquals(ArtifactState.RESOLVED, childPlan.getState()); |
| |
| childPlan.start(); |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| } |
| |
| private void waitUntilActive(Artifact parentPlan) { |
| int i = 0; |
| while (parentPlan.getState() != ArtifactState.ACTIVE) { |
| if (i++ > 10) { |
| // Took too long - give up. |
| assertTrue(false); |
| } |
| try { |
| Thread.sleep(100); |
| } catch (InterruptedException e) { |
| } |
| } |
| } |
| |
| private void checkParentAndChildBundleLifecyclesAreTied(Bundle parentBundle, Bundle childBundle, Artifact parentPlan, Artifact childPlan) { |
| assertEquals(Bundle.ACTIVE, parentBundle.getState()); |
| assertEquals(Bundle.ACTIVE, childBundle.getState()); |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| try { |
| parentBundle.stop(); |
| assertEquals(Bundle.RESOLVED, parentBundle.getState()); |
| assertEquals(Bundle.RESOLVED, childBundle.getState()); |
| |
| parentBundle.start(); |
| assertEquals(Bundle.ACTIVE, parentBundle.getState()); |
| assertEquals(Bundle.ACTIVE, childBundle.getState()); |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| |
| childBundle.stop(); |
| assertEquals(Bundle.RESOLVED, parentBundle.getState()); |
| assertEquals(Bundle.RESOLVED, childBundle.getState()); |
| |
| childBundle.start(); |
| assertEquals(Bundle.ACTIVE, parentBundle.getState()); |
| assertEquals(Bundle.ACTIVE, childBundle.getState()); |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| } catch (BundleException e) { |
| e.printStackTrace(); |
| assertTrue(false); |
| } |
| } |
| |
| private void checkParentAndChildBundleLifecyclesAreIndependent(boolean atomicParentPlan, Bundle parentBundle, Bundle childBundle, |
| Artifact parentPlan, Artifact childPlan) { |
| assertEquals(Bundle.ACTIVE, parentBundle.getState()); |
| assertEquals(Bundle.ACTIVE, childBundle.getState()); |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| try { |
| parentBundle.stop(); |
| assertEquals(Bundle.RESOLVED, parentBundle.getState()); |
| // Stopping the parent bundle stops parent plan if the parent is atomic which stops the child plan, and its |
| // bundles. |
| assertEquals(atomicParentPlan ? Bundle.RESOLVED : Bundle.ACTIVE, childBundle.getState()); |
| |
| parentBundle.start(); |
| assertEquals(Bundle.ACTIVE, parentBundle.getState()); |
| assertEquals(Bundle.ACTIVE, childBundle.getState()); |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| |
| childBundle.stop(); |
| assertEquals(Bundle.ACTIVE, parentBundle.getState()); |
| assertEquals(Bundle.RESOLVED, childBundle.getState()); |
| |
| childBundle.start(); |
| assertEquals(Bundle.ACTIVE, parentBundle.getState()); |
| assertEquals(Bundle.ACTIVE, childBundle.getState()); |
| waitUntilActive(parentPlan); |
| waitUntilActive(childPlan); |
| } catch (BundleException e) { |
| e.printStackTrace(); |
| assertTrue(false); |
| } |
| } |
| |
| private Bundle getSpecificBundle(String bsn, Version version) { |
| Bundle[] bundles = packageAdmin.getBundles(bsn, "[" + version.toString() + ", " + version.toString() + "]"); |
| assertNotNull(bundles); |
| assertEquals(1, bundles.length); |
| return bundles[0]; |
| } |
| |
| /** |
| * The Model class encapsulates the expected behaviour of this testcase. |
| */ |
| private final class Model { |
| |
| private final TestPlanArtifactInfo parent; |
| |
| private final TestPlanArtifactInfo child; |
| |
| public Model(TestPlanArtifactInfo parent) { |
| this.parent = parent; |
| |
| TestPlanArtifactInfo[] childPlans = parent.getChildPlans(); |
| assertEquals(1, childPlans.length); |
| this.child = childPlans[0]; |
| } |
| |
| public boolean importShouldBePromoted() { |
| return this.parent.isScoped(); |
| } |
| |
| public boolean shouldDeployOk() { |
| // A parent and child should deploy ok if and only if they are not both scoped. |
| return !(this.parent.isScoped() && this.child.isScoped()); |
| } |
| |
| public boolean shouldHaveScope() { |
| return shouldChildBeScoped(); |
| } |
| |
| public String getScopeName() { |
| assertTrue(shouldHaveScope()); |
| return getScopeName(this.parent.isScoped() ? this.parent : this.child); |
| } |
| |
| private String getScopeName(TestPlanArtifactInfo scopedPlan) { |
| assertTrue(scopedPlan.isScoped()); |
| StringBuffer scopeName = new StringBuffer(); |
| scopeName.append(scopedPlan.getName() + SCOPE_SEPARATOR + versionToShortString(scopedPlan.getVersion())); |
| return scopeName.toString(); |
| } |
| |
| private String versionToShortString(Version version) { |
| String result = version.toString(); |
| while (result.endsWith(".0")) { |
| result = result.substring(0, result.length() - 2); |
| } |
| return result; |
| } |
| |
| public boolean syntheticContextShouldIncludeParent() { |
| return this.parent.isScoped(); |
| } |
| |
| public boolean syntheticContextShouldIncludeChild() { |
| return shouldChildBeScoped(); |
| } |
| |
| private boolean shouldChildBeScoped() { |
| return this.parent.isScoped() || this.child.isScoped(); |
| } |
| |
| public Bundle getParentBundle() { |
| return getBundle(this.parent, this.parent.isScoped() ? getScopeName() : null); |
| } |
| |
| public Bundle getChildBundle() { |
| return getBundle(this.child, shouldChildBeScoped() ? getScopeName() : null); |
| } |
| |
| private Bundle getBundle(TestPlanArtifactInfo planContainingBundle, String scopeName) { |
| TestArtifactInfo[] childBundles = planContainingBundle.getChildBundles(); |
| assertEquals(1, childBundles.length); |
| TestArtifactInfo childBundle = childBundles[0]; |
| |
| String bsn = childBundle.getName(); |
| Version version = childBundle.getVersion(); |
| |
| if (scopeName != null) { |
| return getSpecificBundle(scopeName + SCOPE_SEPARATOR + bsn, version); |
| } else { |
| return getSpecificBundle(bsn, version); |
| } |
| } |
| |
| } |
| |
| private static TestPlanArtifactInfo[] generateParentPlans(TestArtifactInfo[] children) throws IOException { |
| TestPlanArtifactInfo[] parents = new TestPlanArtifactInfo[16]; |
| int p = 0; |
| for (int c = 0; c < children.length; c++) { |
| for (int s = 0; s < 2; s++) { |
| boolean scopedParent = s == 1; |
| for (int a = 0; a < 2; a++) { |
| boolean atomicParent = a == 1; |
| TestArtifactInfo childPlan = children[c]; |
| String parentName = parentPlanName(scopedParent, atomicParent, childPlan); |
| parents[p++] = createPlanFile(parentName, DEFAULT_VERSION, scopedParent, atomicParent, PARENT_BUNDLE_INFO, childPlan); |
| } |
| } |
| } |
| return parents; |
| } |
| |
| private static TestPlanArtifactInfo[] generateChildPlans() throws IOException { |
| TestPlanArtifactInfo[] children = new TestPlanArtifactInfo[4]; |
| int c = 0; |
| for (int s = 0; s < 2; s++) { |
| boolean scopedChild = s == 1; |
| for (int a = 0; a < 2; a++) { |
| boolean atomicChild = a == 1; |
| String childName = childPlanName(scopedChild, atomicChild); |
| children[c++] = createPlanFile(childName, DEFAULT_VERSION, scopedChild, atomicChild, CHILD_BUNDLE_INFO); |
| } |
| } |
| return children; |
| } |
| |
| private static String childPlanName(boolean scopedChild, boolean atomicChild) { |
| return scopingAtomicityName(scopedChild, atomicChild) + ".child"; |
| } |
| |
| private static String parentPlanName(boolean scopedParent, boolean atomicParent, TestArtifactInfo childPlan) { |
| return scopingAtomicityName(scopedParent, atomicParent) + ".parentOf." + childPlan.getName(); |
| } |
| |
| private static String scopingAtomicityName(boolean scoped, boolean atomic) { |
| return (scoped ? "scoped" : "unscoped") + "." + (atomic ? "atomic" : "nonatomic"); |
| } |
| |
| private DeploymentIdentity deploy(TestArtifactInfo artifact) throws DeploymentException { |
| DeploymentIdentity identity = this.deployer.deploy(artifact.getFile().toURI()); |
| Assert.assertEquals(artifact.getType(), identity.getType()); |
| Assert.assertEquals(artifact.getName(), identity.getSymbolicName()); |
| Assert.assertEquals(artifact.getVersion(), new Version(identity.getVersion())); |
| return identity; |
| } |
| |
| public static TestPlanArtifactInfo createPlanFile(String planName, Version planVersion, boolean scoped, boolean atomic, TestArtifactInfo... children) throws IOException { |
| StringBuffer planContent = new StringBuffer(1024); |
| planContent.append(XML_HEADER); |
| planContent.append("<plan name=\"" + planName + "\" version=\"" + planVersion + "\" scoped=\"" + new Boolean(scoped) + "\" atomic=\"" + new Boolean(atomic) + "\" \n" + NAMESPACES + ">\n"); |
| |
| for (TestArtifactInfo childInfo : children) { |
| Version childVersion = childInfo.getVersion(); |
| planContent.append(" <artifact type=\"" + childInfo.getType() + "\" name=\"" + childInfo.getName() + "\" version=\"[" + childVersion + ", " + childVersion + "]\"/>\n"); |
| } |
| |
| planContent.append("</plan>"); |
| |
| TestPlanArtifactInfo info = new TestPlanArtifactInfo(planName, planVersion, scoped, atomic, children); |
| |
| String fileName = planName + "-" + planVersion + PLAN_EXTENSION; |
| File planFile = new File(GENERATED_PLAN_DIRECTORY + fileName); |
| Writer writer = new FileWriter(planFile); |
| try { |
| writer.write(planContent.toString()); |
| } finally { |
| writer.close(); |
| } |
| |
| info.setFile(planFile); |
| |
| return info; |
| } |
| |
| private static final class TestPlanArtifactInfo extends TestArtifactInfo { |
| |
| private static final TestPlanArtifactInfo[] EMPTY_CHILD_PLAN_ARRAY = new TestPlanArtifactInfo[0]; |
| |
| private final boolean scoped; |
| |
| private final boolean atomic; |
| |
| public TestPlanArtifactInfo(String name, Version version, Boolean scoped, Boolean atomic, TestArtifactInfo[] children) { |
| super(PLAN_TYPE, name, version, children); |
| this.scoped = scoped; |
| this.atomic = atomic; |
| } |
| |
| public TestPlanArtifactInfo[] getChildPlans() { |
| List<TestPlanArtifactInfo> childPlans = new ArrayList<TestPlanArtifactInfo>(); |
| for (TestArtifactInfo child : getChildren()) { |
| if (child instanceof TestPlanArtifactInfo) { |
| childPlans.add((TestPlanArtifactInfo) child); |
| } |
| } |
| return childPlans.toArray(EMPTY_CHILD_PLAN_ARRAY); |
| } |
| |
| public TestPlanArtifactInfo getChildPlan() { |
| TestPlanArtifactInfo[] childPlans = getChildPlans(); |
| assertEquals(1, childPlans.length); |
| return childPlans[0]; |
| } |
| |
| public boolean isScoped() { |
| return scoped; |
| } |
| |
| public boolean isAtomic() { |
| return atomic; |
| } |
| |
| } |
| |
| private static class TestArtifactInfo { |
| |
| private static final TestArtifactInfo[] EMPTY_CHILD_ARRAY = new TestArtifactInfo[0]; |
| |
| private final String type; |
| |
| private final String name; |
| |
| private final Version version; |
| |
| private File file; |
| |
| private TestArtifactInfo[] children; |
| |
| public TestArtifactInfo(String type, String name, Version version, TestArtifactInfo[] children) { |
| this.type = type; |
| this.name = name; |
| this.version = version; |
| this.children = children == null ? EMPTY_CHILD_ARRAY : children; |
| } |
| |
| public TestArtifactInfo(String type, String name, Version version) { |
| this(type, name, version, null); |
| } |
| |
| public String getType() { |
| return type; |
| } |
| |
| public String getName() { |
| return name; |
| } |
| |
| public Version getVersion() { |
| return version; |
| } |
| |
| public TestArtifactInfo[] getChildren() { |
| return this.children; |
| } |
| |
| public TestArtifactInfo[] getChildBundles() { |
| List<TestArtifactInfo> childBundles = new ArrayList<TestArtifactInfo>(); |
| for (TestArtifactInfo child : getChildren()) { |
| if (BUNDLE_TYPE.equals(child.getType())) { |
| childBundles.add(child); |
| } |
| } |
| return childBundles.toArray(EMPTY_CHILD_ARRAY); |
| } |
| |
| public void setFile(File file) { |
| this.file = file; |
| } |
| |
| public File getFile() { |
| if (this.file == null) { |
| throw new IllegalStateException("TestArtifactInfo file not set"); |
| } |
| return file; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public String toString() { |
| return /* "TestArtifactInfo [type=" + type + ", name=" + */name /* + ", version=" + version + "]" */; |
| } |
| |
| } |
| |
| } |