/******************************************************************************* * Copyright (c) 2011, 2015 VMware Inc. and others * 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: * SpringSource, a division of VMware - initial API and implementation and/or initial documentation *******************************************************************************/ package org.eclipse.equinox.region.internal.tests.hook; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.*; import org.eclipse.equinox.region.*; import org.eclipse.equinox.region.internal.tests.RegionReflectionUtils; import org.eclipse.virgo.teststubs.osgi.framework.*; import org.junit.*; import org.osgi.framework.*; import org.osgi.framework.hooks.service.EventHook; /** * This testcase was based on {@link RegionBundleFindHookTests}. */ public class RegionServiceEventHookTests { private static final String BUNDLE_X = "X"; private static final Version BUNDLE_VERSION = new Version("0"); private long bundleId; private static final String REGION_A = "RegionA"; private static final String BUNDLE_A = "BundleA"; private static final String REGION_B = "RegionB"; private static final String BUNDLE_B = "BundleB"; private static final String REGION_C = "RegionC"; private static final String BUNDLE_C = "BundleC"; private static final String REGION_D = "RegionD"; private static final String BUNDLE_D = "BundleD"; private static final String DUPLICATE = "Duplicate"; private static final String DUPLICATE_FIlTER = DUPLICATE + "*"; private RegionDigraph digraph; @SuppressWarnings("deprecation") private EventHook serviceEventHook; private Map<String, Region> regions; private Map<String, Bundle> bundles; private Map<String, ServiceReference<Object>> serviceReferences; private ThreadLocal<Region> threadLocal; @Before public void setUp() throws Exception { this.bundleId = 1L; this.regions = new HashMap<String, Region>(); this.bundles = new HashMap<String, Bundle>(); this.serviceReferences = new HashMap<String, ServiceReference<Object>>(); StubBundle stubSystemBundle = new StubBundle(0L, "osgi.framework", new Version("0"), "loc"); StubBundleContext stubBundleContext = new StubBundleContext(); stubBundleContext.addInstalledBundle(stubSystemBundle); this.threadLocal = new ThreadLocal<Region>(); this.digraph = RegionReflectionUtils.newStandardRegionDigraph(stubBundleContext, this.threadLocal); this.serviceEventHook = RegionReflectionUtils.newRegionServiceEventHook(this.digraph); // Create regions A, B, C, D containing bundles A, B, C, D, respectively. createRegion(REGION_A, BUNDLE_A); createRegion(REGION_B, BUNDLE_B); createRegion(REGION_C, BUNDLE_C); createRegion(REGION_D, BUNDLE_D); createBundle(BUNDLE_X); } @After public void tearDown() throws Exception { // nothing } @Test public void testEventInSameRegion() { Collection<BundleContext> contexts = bundleContexts(BUNDLE_A); this.serviceEventHook.event(serviceEvent(BUNDLE_A), contexts); assertTrue(contexts.contains(bundleContext(BUNDLE_A))); } @Test public void testEventInDisconnectedRegion() { Collection<BundleContext> contexts = bundleContexts(BUNDLE_A); this.serviceEventHook.event(serviceEvent(BUNDLE_B), contexts); assertFalse(contexts.contains(bundleContext(BUNDLE_A))); } @Test public void testEventConnectedRegionAllowed() throws BundleException, InvalidSyntaxException { RegionFilter filter = createFilter(BUNDLE_B); region(REGION_A).connectRegion(region(REGION_B), filter); Collection<BundleContext> contexts = bundleContexts(BUNDLE_A); this.serviceEventHook.event(serviceEvent(BUNDLE_B), contexts); assertTrue(contexts.contains(bundleContext(BUNDLE_A))); } @Test public void testEventConnectedRegionFiltering() throws BundleException, InvalidSyntaxException { region(REGION_A).connectRegion(region(REGION_B), createFilter(BUNDLE_B)); Bundle x = createBundle(BUNDLE_X); region(REGION_B).addBundle(x); Collection<BundleContext> contexts = bundleContexts(BUNDLE_A, BUNDLE_B, BUNDLE_X); this.serviceEventHook.event(serviceEvent(BUNDLE_X), contexts); assertTrue(contexts.contains(bundleContext(BUNDLE_B))); assertTrue(contexts.contains(bundleContext(BUNDLE_X))); assertFalse(contexts.contains(bundleContext(BUNDLE_A))); } @Test public void testEventTransitive() throws BundleException, InvalidSyntaxException { region(REGION_A).connectRegion(region(REGION_B), createFilter(BUNDLE_C)); region(REGION_B).connectRegion(region(REGION_C), createFilter(BUNDLE_C)); region(REGION_C).addBundle(bundle(BUNDLE_X)); Collection<BundleContext> contexts = bundleContexts(BUNDLE_A, BUNDLE_B, BUNDLE_X); this.serviceEventHook.event(serviceEvent(BUNDLE_C), contexts); assertTrue(contexts.contains(bundleContext(BUNDLE_B))); assertTrue(contexts.contains(bundleContext(BUNDLE_X))); assertTrue(contexts.contains(bundleContext(BUNDLE_A))); contexts = bundleContexts(BUNDLE_A, BUNDLE_B, BUNDLE_X); this.serviceEventHook.event(serviceEvent(BUNDLE_X), contexts); assertFalse(contexts.contains(bundleContext(BUNDLE_B))); assertTrue(contexts.contains(bundleContext(BUNDLE_X))); assertFalse(contexts.contains(bundleContext(BUNDLE_A))); } @Test public void testEventTransitiveDups() throws BundleException, InvalidSyntaxException { region(REGION_A).connectRegion(region(REGION_B), createFilter(BUNDLE_C)); region(REGION_A).connectRegion(region(REGION_C), createFilter(DUPLICATE_FIlTER)); region(REGION_A).connectRegion(region(REGION_D), createFilter(DUPLICATE_FIlTER)); region(REGION_B).connectRegion(region(REGION_C), createFilter(DUPLICATE_FIlTER)); region(REGION_C).connectRegion(region(REGION_D), createFilter(DUPLICATE_FIlTER)); region(REGION_D).connectRegion(region(REGION_A), createFilter(DUPLICATE_FIlTER)); Collection<BundleContext> contexts = bundleContexts(BUNDLE_A); this.serviceEventHook.event(serviceEvent(DUPLICATE + bundle(BUNDLE_A).getBundleId()), contexts); assertTrue(contexts.contains(bundleContext(BUNDLE_A))); contexts = bundleContexts(BUNDLE_A); this.serviceEventHook.event(serviceEvent(DUPLICATE + bundle(BUNDLE_B).getBundleId()), contexts); assertFalse(contexts.contains(bundleContext(BUNDLE_A))); contexts = bundleContexts(BUNDLE_A); this.serviceEventHook.event(serviceEvent(DUPLICATE + bundle(BUNDLE_C).getBundleId()), contexts); assertTrue(contexts.contains(bundleContext(BUNDLE_A))); contexts = bundleContexts(BUNDLE_A); this.serviceEventHook.event(serviceEvent(DUPLICATE + bundle(BUNDLE_D).getBundleId()), contexts); assertTrue(contexts.contains(bundleContext(BUNDLE_A))); } @Test public void testEventInCyclicGraph() throws BundleException, InvalidSyntaxException { region(REGION_D).addBundle(bundle(BUNDLE_X)); region(REGION_A).connectRegion(region(REGION_B), createFilter(BUNDLE_D, BUNDLE_X)); region(REGION_B).connectRegion(region(REGION_A), createFilter()); region(REGION_B).connectRegion(region(REGION_D), createFilter(BUNDLE_D)); region(REGION_D).connectRegion(region(REGION_B), createFilter()); region(REGION_B).connectRegion(region(REGION_C), createFilter(BUNDLE_X)); region(REGION_C).connectRegion(region(REGION_B), createFilter()); region(REGION_C).connectRegion(region(REGION_D), createFilter(BUNDLE_X)); region(REGION_D).connectRegion(region(REGION_C), createFilter()); region(REGION_A).connectRegion(region(REGION_C), createFilter()); region(REGION_C).connectRegion(region(REGION_A), createFilter()); region(REGION_D).connectRegion(region(REGION_A), createFilter()); region(REGION_A).connectRegion(region(REGION_D), createFilter()); Collection<BundleContext> contexts = bundleContexts(BUNDLE_A, BUNDLE_B); this.serviceEventHook.event(serviceEvent(BUNDLE_B), contexts); assertFalse(contexts.contains(bundleContext(BUNDLE_A))); assertTrue(contexts.contains(bundleContext(BUNDLE_B))); contexts = bundleContexts(BUNDLE_A, BUNDLE_B); this.serviceEventHook.event(serviceEvent(BUNDLE_C), contexts); assertFalse(contexts.contains(bundleContext(BUNDLE_A))); assertFalse(contexts.contains(bundleContext(BUNDLE_B))); contexts = bundleContexts(BUNDLE_A, BUNDLE_B); this.serviceEventHook.event(serviceEvent(BUNDLE_D), contexts); assertTrue(contexts.contains(bundleContext(BUNDLE_A))); assertTrue(contexts.contains(bundleContext(BUNDLE_B))); contexts = bundleContexts(BUNDLE_A, BUNDLE_B); this.serviceEventHook.event(serviceEvent(BUNDLE_X), contexts); assertTrue(contexts.contains(bundleContext(BUNDLE_A))); assertTrue(contexts.contains(bundleContext(BUNDLE_B))); } @Test public void testEventFromSystemBundle() { Bundle systemBundle = new StubBundle(0L, "sys", BUNDLE_VERSION, ""); Collection<BundleContext> contexts = new ArrayList<BundleContext>(Arrays.asList(systemBundle.getBundleContext())); this.serviceEventHook.event(serviceEvent(BUNDLE_A), contexts); assertTrue(contexts.contains(systemBundle.getBundleContext())); } @Test public void testEventFromBundleInNoRegion() { Bundle stranger = createBundle("stranger"); Collection<BundleContext> contexts = new ArrayList<BundleContext>(Arrays.asList(stranger.getBundleContext())); this.serviceEventHook.event(serviceEvent(BUNDLE_A), contexts); assertTrue(contexts.isEmpty()); } private Region createRegion(String regionName, String... bundleSymbolicNames) throws BundleException { Region region = this.digraph.createRegion(regionName); for (String bundleSymbolicName : bundleSymbolicNames) { Bundle stubBundle = createBundle(bundleSymbolicName); region.addBundle(stubBundle); } this.regions.put(regionName, region); return region; } private Region region(String regionName) { return this.regions.get(regionName); } private RegionFilter createFilter(final String... referenceNames) throws InvalidSyntaxException { Collection<String> filters = new ArrayList<String>(referenceNames.length); for (String referenceName : referenceNames) { filters.add('(' + Constants.OBJECTCLASS + '=' + referenceName + ')'); } RegionFilterBuilder builder = digraph.createRegionFilterBuilder(); for (String filter : filters) { builder.allow(RegionFilter.VISIBLE_SERVICE_NAMESPACE, filter); } String negateFilter = "(!(|" + "(" + RegionFilter.VISIBLE_ALL_NAMESPACE_ATTRIBUTE + "=" + RegionFilter.VISIBLE_SERVICE_NAMESPACE + ")" + "(" + RegionFilter.VISIBLE_ALL_NAMESPACE_ATTRIBUTE + "=" + RegionFilter.VISIBLE_BUNDLE_NAMESPACE + ")" + "))"; builder.allow(RegionFilter.VISIBLE_ALL_NAMESPACE, negateFilter); return builder.build(); } private Bundle createBundle(String bundleSymbolicName) { Bundle stubBundle = new StubBundle(this.bundleId++, bundleSymbolicName, BUNDLE_VERSION, "loc:" + bundleSymbolicName); this.bundles.put(bundleSymbolicName, stubBundle); createServiceReference(stubBundle, bundleSymbolicName); return stubBundle; } private StubServiceReference<Object> createServiceReference(Bundle stubBundle, String referenceName) { StubServiceRegistration<Object> stubServiceRegistration = new StubServiceRegistration<Object>((StubBundleContext) stubBundle.getBundleContext(), referenceName); StubServiceReference<Object> stubServiceReference = new StubServiceReference<Object>(stubServiceRegistration); this.serviceReferences.put(referenceName, stubServiceReference); StubServiceRegistration<Object> dupServiceRegistration = new StubServiceRegistration<Object>((StubBundleContext) stubBundle.getBundleContext(), DUPLICATE + stubBundle.getBundleId()); StubServiceReference<Object> dupServiceReference = new StubServiceReference<Object>(dupServiceRegistration); this.serviceReferences.put(DUPLICATE + stubBundle.getBundleId(), dupServiceReference); return stubServiceReference; } private Collection<BundleContext> bundleContexts(String... bundleSymbolicNames) { Collection<BundleContext> contexts = new ArrayList<BundleContext>(); for (String symbolicName : bundleSymbolicNames) { contexts.add(bundleContext(symbolicName)); } return contexts; } private BundleContext bundleContext(String bundleSymbolicName) { return bundle(bundleSymbolicName).getBundleContext(); } private Bundle bundle(String bundleSymbolicName) { Bundle bundleA = this.bundles.get(bundleSymbolicName); return bundleA; } private ServiceEvent serviceEvent(String referenceName) { return new ServiceEvent(ServiceEvent.REGISTERED, serviceReference(referenceName)); } private ServiceReference<Object> serviceReference(String referenceName) { return this.serviceReferences.get(referenceName); } }