Bug 476145 - [region] performance issue with large number of bundle listeners and bundle events
diff --git a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/internal/tests/RegionReflectionUtils.java b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/internal/tests/RegionReflectionUtils.java
index 87a13f5..e33d2d2 100644
--- a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/internal/tests/RegionReflectionUtils.java
+++ b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/internal/tests/RegionReflectionUtils.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2013 IBM Corporation and others.
+ * Copyright (c) 2013, 2015 IBM Corporation 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
@@ -172,10 +172,10 @@
return (CollisionHook) newInstance(regionBundleCollisionHook, classParams, constructorArgs);
}
- public static EventHook newRegionBundleEventHook(RegionDigraph digraph, FindHook findHook, ThreadLocal<Region> threadLocal) {
+ public static EventHook newRegionBundleEventHook(RegionDigraph digraph, ThreadLocal<Region> threadLocal, long bundleId) {
Class<?> regionBundleEventHook = loadRegionImplClass(RegionBundleEventHook);
- Class<?>[] classParams = new Class<?>[] {RegionDigraph.class, FindHook.class, ThreadLocal.class};
- Object[] constructorArgs = new Object[] {digraph, findHook, threadLocal};
+ Class<?>[] classParams = new Class<?>[] {RegionDigraph.class, ThreadLocal.class, long.class};
+ Object[] constructorArgs = new Object[] {digraph, threadLocal, bundleId};
return (EventHook) newInstance(regionBundleEventHook, classParams, constructorArgs);
}
diff --git a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/internal/tests/hook/RegionBundleEventHookTests.java b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/internal/tests/hook/RegionBundleEventHookTests.java
index 38f0de4..a6047b2 100644
--- a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/internal/tests/hook/RegionBundleEventHookTests.java
+++ b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/internal/tests/hook/RegionBundleEventHookTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2011, 2013 VMware Inc.
+ * 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
@@ -11,76 +11,72 @@
package org.eclipse.equinox.region.internal.tests.hook;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import java.util.Collection;
-import java.util.HashSet;
-import org.easymock.EasyMock;
-import org.eclipse.equinox.region.Region;
-import org.eclipse.equinox.region.RegionDigraph;
+import java.util.*;
+import org.eclipse.equinox.region.*;
import org.eclipse.equinox.region.internal.tests.RegionReflectionUtils;
import org.eclipse.virgo.teststubs.osgi.framework.StubBundle;
import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext;
import org.junit.*;
import org.osgi.framework.*;
import org.osgi.framework.hooks.bundle.EventHook;
-import org.osgi.framework.hooks.bundle.FindHook;
public class RegionBundleEventHookTests {
- private BundleEvent bundleEvent;
+ private static final String BUNDLE_X = "X";
- private Collection<BundleContext> contexts;
+ private static final Version BUNDLE_VERSION = new Version("0");
- private Bundle eventBundle;
+ private long bundleId;
- private RegionDigraph mockRegionDigraph;
+ private static final String REGION_A = "RegionA";
- private ThreadLocal<Region> threadLocal;
+ 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 RegionDigraph digraph;
- private Region mockRegion1;
+ private EventHook bundleEventHook;
- private Region mockRegion2;
+ private Map<String, Region> regions;
- private BundleEvent installedEvent1;
+ private Map<String, Bundle> bundles;
- private BundleEvent installedEvent2;
-
- private StubBundle eventBundle1;
-
- private StubBundle eventBundle2;
+ private ThreadLocal<Region> threadLocal;
@Before
public void setUp() throws Exception {
- this.mockRegionDigraph = EasyMock.createMock(RegionDigraph.class);
- this.eventBundle = new StubBundle();
-
- this.eventBundle1 = new StubBundle(1L, "my.bundle1", new Version("0"), "loc1");
- this.eventBundle2 = new StubBundle(2L, "my.bundle2", new Version("0"), "loc2");
-
- this.bundleEvent = new BundleEvent(BundleEvent.STARTED, this.eventBundle, this.eventBundle);
-
- this.installedEvent1 = new BundleEvent(BundleEvent.INSTALLED, eventBundle1, this.eventBundle);
- this.installedEvent2 = new BundleEvent(BundleEvent.INSTALLED, eventBundle2, this.eventBundle);
-
- this.contexts = new HashSet<BundleContext>();
- StubBundleContext stubListenerBundleContext = new StubBundleContext();
- this.contexts.add(stubListenerBundleContext);
- this.threadLocal = new ThreadLocal<Region>();
+ this.bundleId = 1L;
+ this.regions = new HashMap<String, Region>();
+ this.bundles = new HashMap<String, Bundle>();
StubBundle stubSystemBundle = new StubBundle(0L, "osgi.framework", new Version("0"), "loc");
StubBundleContext stubBundleContext = new StubBundleContext();
stubBundleContext.addInstalledBundle(stubSystemBundle);
- this.digraph = RegionReflectionUtils.newStandardRegionDigraph(stubBundleContext, new ThreadLocal<Region>());
- this.digraph.createRegion("mockRegion1");
- this.digraph.createRegion("mockRegion2");
- this.mockRegion1 = digraph.getRegion("mockRegion1");
- this.mockRegion2 = digraph.getRegion("mockRegion2");
- this.mockRegion1.addBundle(this.eventBundle);
+ this.threadLocal = new ThreadLocal<Region>();
+ this.digraph = RegionReflectionUtils.newStandardRegionDigraph(stubBundleContext, this.threadLocal);
+ this.bundleEventHook = RegionReflectionUtils.newRegionBundleEventHook(digraph, threadLocal, stubSystemBundle.getBundleId());
+ // 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
@@ -89,53 +85,225 @@
}
@Test
- public void testEventAllowed() {
- FindHook mockFindHook = new FindHook() {
-
- @Override
- public void find(BundleContext context, Collection<Bundle> bundles) {
- // nothing
- }
- };
- EventHook eventHook = RegionReflectionUtils.newRegionBundleEventHook(this.mockRegionDigraph, mockFindHook, this.threadLocal);
- eventHook.event(this.bundleEvent, this.contexts);
- assertEquals(1, this.contexts.size());
+ public void testEventInSameRegion() {
+ Collection<BundleContext> contexts = bundleContexts(BUNDLE_A);
+ this.bundleEventHook.event(bundleEvent(BUNDLE_A), contexts);
+ assertTrue(contexts.contains(bundleContext(BUNDLE_A)));
}
@Test
- public void testEventNotAllowed() {
- FindHook mockFindHook = new FindHook() {
+ public void testEventInDisconnectedRegion() {
+ Collection<BundleContext> contexts = bundleContexts(BUNDLE_A);
+ this.bundleEventHook.event(bundleEvent(BUNDLE_B), contexts);
+ assertFalse(contexts.contains(bundleContext(BUNDLE_A)));
+ }
- @Override
- public void find(BundleContext context, Collection<Bundle> bundles) {
- bundles.clear();
- }
- };
- EventHook eventHook = RegionReflectionUtils.newRegionBundleEventHook(this.mockRegionDigraph, mockFindHook, this.threadLocal);
- eventHook.event(this.bundleEvent, this.contexts);
- assertTrue(this.contexts.isEmpty());
+ @Test
+ public void testEventConnectedRegionAllowed() throws BundleException, InvalidSyntaxException {
+ doTestEventConnectedRegionAllowed(false);
+ }
+
+ @Test
+ public void testEventConnectedRegionAllowedWithNegate() throws BundleException, InvalidSyntaxException {
+ doTestEventConnectedRegionAllowed(true);
+ }
+
+ private void doTestEventConnectedRegionAllowed(boolean negate) throws BundleException, InvalidSyntaxException {
+ RegionFilter filter = createFilter(negate, BUNDLE_B);
+ region(REGION_A).connectRegion(region(REGION_B), filter);
+
+ Collection<BundleContext> contexts = bundleContexts(BUNDLE_A);
+ this.bundleEventHook.event(bundleEvent(BUNDLE_B), contexts);
+ assertTrue(contexts.contains(bundleContext(BUNDLE_A)));
+ }
+
+ @Test
+ public void testEventConnectedRegionFiltering() throws BundleException, InvalidSyntaxException {
+ doTestEventConnectedRegionFiltering(false);
+ }
+
+ @Test
+ public void testEventConnectedRegionFilteringWithNegate() throws BundleException, InvalidSyntaxException {
+ doTestEventConnectedRegionFiltering(true);
+ }
+
+ private void doTestEventConnectedRegionFiltering(boolean negate) throws BundleException, InvalidSyntaxException {
+ region(REGION_A).connectRegion(region(REGION_B), createFilter(negate, BUNDLE_B));
+ Bundle x = createBundle(BUNDLE_X);
+ region(REGION_B).addBundle(x);
+
+ Collection<BundleContext> contexts = bundleContexts(BUNDLE_A, BUNDLE_B, BUNDLE_X);
+ this.bundleEventHook.event(bundleEvent(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 {
+ doTestEventTransitive(false);
+ }
+
+ @Test
+ public void testEventTransitiveWithNegate() throws BundleException, InvalidSyntaxException {
+ doTestEventTransitive(true);
+ }
+
+ private void doTestEventTransitive(boolean negate) throws BundleException, InvalidSyntaxException {
+ region(REGION_A).connectRegion(region(REGION_B), createFilter(negate, BUNDLE_C));
+ region(REGION_B).connectRegion(region(REGION_C), createFilter(negate, BUNDLE_C));
+ region(REGION_C).addBundle(bundle(BUNDLE_X));
+
+ Collection<BundleContext> contexts = bundleContexts(BUNDLE_A, BUNDLE_B, BUNDLE_X);
+ this.bundleEventHook.event(bundleEvent(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.bundleEventHook.event(bundleEvent(BUNDLE_X), contexts);
+ assertFalse(contexts.contains(bundleContext(BUNDLE_B)));
+ assertTrue(contexts.contains(bundleContext(BUNDLE_X)));
+ assertFalse(contexts.contains(bundleContext(BUNDLE_A)));
+ }
+
+ @Test
+ public void testEventInCyclicGraph() throws BundleException, InvalidSyntaxException {
+ doTestEventInCyclicGraph(false);
+ }
+
+ @Test
+ public void testEventInCyclicGraphWithNegate() throws BundleException, InvalidSyntaxException {
+
+ doTestEventInCyclicGraph(true);
+ }
+
+ private void doTestEventInCyclicGraph(boolean negate) throws BundleException, InvalidSyntaxException {
+ region(REGION_D).addBundle(bundle(BUNDLE_X));
+
+ region(REGION_A).connectRegion(region(REGION_B), createFilter(negate, BUNDLE_D, BUNDLE_X));
+ region(REGION_B).connectRegion(region(REGION_A), createFilter(negate));
+
+ region(REGION_B).connectRegion(region(REGION_D), createFilter(negate, BUNDLE_D));
+ region(REGION_D).connectRegion(region(REGION_B), createFilter(negate));
+
+ region(REGION_B).connectRegion(region(REGION_C), createFilter(negate, BUNDLE_X));
+ region(REGION_C).connectRegion(region(REGION_B), createFilter(negate));
+
+ region(REGION_C).connectRegion(region(REGION_D), createFilter(negate, BUNDLE_X));
+ region(REGION_D).connectRegion(region(REGION_C), createFilter(negate));
+
+ region(REGION_A).connectRegion(region(REGION_C), createFilter(negate));
+ region(REGION_C).connectRegion(region(REGION_A), createFilter(negate));
+
+ region(REGION_D).connectRegion(region(REGION_A), createFilter(negate));
+ region(REGION_A).connectRegion(region(REGION_D), createFilter(negate));
+
+ Collection<BundleContext> contexts = bundleContexts(BUNDLE_A, BUNDLE_B);
+ this.bundleEventHook.event(bundleEvent(BUNDLE_B), contexts);
+ assertFalse(contexts.contains(bundleContext(BUNDLE_A)));
+ assertTrue(contexts.contains(bundleContext(BUNDLE_B)));
+
+ contexts = bundleContexts(BUNDLE_A, BUNDLE_B);
+ this.bundleEventHook.event(bundleEvent(BUNDLE_C), contexts);
+ assertFalse(contexts.contains(bundleContext(BUNDLE_A)));
+ assertFalse(contexts.contains(bundleContext(BUNDLE_B)));
+
+ contexts = bundleContexts(BUNDLE_A, BUNDLE_B);
+ this.bundleEventHook.event(bundleEvent(BUNDLE_D), contexts);
+ assertTrue(contexts.contains(bundleContext(BUNDLE_A)));
+ assertTrue(contexts.contains(bundleContext(BUNDLE_B)));
+
+ contexts = bundleContexts(BUNDLE_A, BUNDLE_B);
+ this.bundleEventHook.event(bundleEvent(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.bundleEventHook.event(bundleEvent(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.bundleEventHook.event(bundleEvent(BUNDLE_A), contexts);
+ assertTrue(contexts.isEmpty());
}
@Test
public void testDefaultRegion() {
- FindHook mockFindHook = new FindHook() {
-
- @Override
- public void find(BundleContext context, Collection<Bundle> bundles) {
- bundles.clear();
- }
- };
-
this.digraph.setDefaultRegion(null);
- EventHook eventHook = RegionReflectionUtils.newRegionBundleEventHook(this.digraph, mockFindHook, this.threadLocal);
- eventHook.event(this.installedEvent1, this.contexts);
- assertTrue(this.digraph.getRegion(this.eventBundle1).equals(this.mockRegion1));
+ Bundle x = createBundle("installed.X");
+ this.bundleEventHook.event(new BundleEvent(BundleEvent.INSTALLED, x, bundle(BUNDLE_A)), Collections.<BundleContext> emptyList());
+ assertTrue(this.digraph.getRegion(x).equals(region(REGION_A)));
- this.digraph.setDefaultRegion(this.mockRegion2);
- eventHook = RegionReflectionUtils.newRegionBundleEventHook(this.digraph, mockFindHook, this.threadLocal);
- eventHook.event(this.installedEvent2, this.contexts);
- assertTrue(this.digraph.getRegion(this.eventBundle2).equals(this.mockRegion2));
-
+ this.digraph.setDefaultRegion(region(REGION_B));
+ Bundle y = createBundle("installed.Y");
+ this.bundleEventHook.event(new BundleEvent(BundleEvent.INSTALLED, y, bundle(BUNDLE_A)), Collections.<BundleContext> emptyList());
+ assertTrue(this.digraph.getRegion(y).equals(region(REGION_B)));
}
+ 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(boolean negate, String... bundleSymbolicNames) throws InvalidSyntaxException {
+ Collection<String> filters = new ArrayList<String>(bundleSymbolicNames.length);
+ for (String bundleSymbolicName : bundleSymbolicNames) {
+ filters.add('(' + RegionFilter.VISIBLE_BUNDLE_NAMESPACE + '=' + bundleSymbolicName + ')');
+ }
+ RegionFilterBuilder builder = digraph.createRegionFilterBuilder();
+ for (String filter : filters) {
+ builder.allow(RegionFilter.VISIBLE_BUNDLE_NAMESPACE, filter);
+ }
+
+ if (negate) {
+ String negateFilter = "(!(|" + "(" + RegionFilter.VISIBLE_ALL_NAMESPACE_ATTRIBUTE + "=" + RegionFilter.VISIBLE_BUNDLE_NAMESPACE + ")" + "(" + RegionFilter.VISIBLE_ALL_NAMESPACE_ATTRIBUTE + "=" + RegionFilter.VISIBLE_BUNDLE_LIFECYCLE_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);
+ return stubBundle;
+ }
+
+ 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 BundleEvent bundleEvent(String budnleSymbolicName) {
+ return new BundleEvent(BundleEvent.STARTED, bundle(budnleSymbolicName));
+ }
+
+ private Bundle bundle(String bundleSymbolicName) {
+ Bundle bundleA = this.bundles.get(bundleSymbolicName);
+ return bundleA;
+ }
}
diff --git a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/internal/tests/hook/RegionServiceEventHookTests.java b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/internal/tests/hook/RegionServiceEventHookTests.java
index cb0758b..014370f 100644
--- a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/internal/tests/hook/RegionServiceEventHookTests.java
+++ b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/internal/tests/hook/RegionServiceEventHookTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2011, 2015 VMware Inc.
+ * 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
@@ -94,21 +94,21 @@
}
@Test
- public void testFindInSameRegion() {
+ 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 testFindInDisconnectedRegion() {
+ 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 testFindConnectedRegionAllowed() throws BundleException, InvalidSyntaxException {
+ public void testEventConnectedRegionAllowed() throws BundleException, InvalidSyntaxException {
RegionFilter filter = createFilter(BUNDLE_B);
region(REGION_A).connectRegion(region(REGION_B), filter);
@@ -118,7 +118,7 @@
}
@Test
- public void testFindConnectedRegionFiltering() throws BundleException, InvalidSyntaxException {
+ 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);
@@ -131,7 +131,7 @@
}
@Test
- public void testFindTransitive() throws BundleException, InvalidSyntaxException {
+ 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));
@@ -147,11 +147,10 @@
assertFalse(contexts.contains(bundleContext(BUNDLE_B)));
assertTrue(contexts.contains(bundleContext(BUNDLE_X)));
assertFalse(contexts.contains(bundleContext(BUNDLE_A)));
-
}
@Test
- public void testFindTransitiveDups() throws BundleException, InvalidSyntaxException {
+ 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));
@@ -177,7 +176,7 @@
}
@Test
- public void testFindInCyclicGraph() throws BundleException, InvalidSyntaxException {
+ 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));
@@ -220,7 +219,7 @@
}
@Test
- public void testFindFromSystemBundle() {
+ 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);
@@ -228,7 +227,7 @@
}
@Test
- public void testFindFromBundleInNoRegion() {
+ public void testEventFromBundleInNoRegion() {
Bundle stranger = createBundle("stranger");
Collection<BundleContext> contexts = new ArrayList<BundleContext>(Arrays.asList(stranger.getBundleContext()));
this.serviceEventHook.event(serviceEvent(BUNDLE_A), contexts);
diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/equinox/internal/region/StandardRegionDigraph.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/equinox/internal/region/StandardRegionDigraph.java
index e592370..fedb941 100644
--- a/bundles/org.eclipse.equinox.region/src/org/eclipse/equinox/internal/region/StandardRegionDigraph.java
+++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/equinox/internal/region/StandardRegionDigraph.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2011, 2014 VMware Inc.
+ * 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
@@ -87,7 +87,7 @@
this.resolverHookFactory = new RegionResolverHookFactory(this);
this.bundleFindHook = new RegionBundleFindHook(this, bundleContext == null ? 0 : bundleContext.getBundle().getBundleId());
- this.bundleEventHook = new RegionBundleEventHook(this, this.bundleFindHook, this.threadLocal);
+ this.bundleEventHook = new RegionBundleEventHook(this, this.threadLocal, bundleContext == null ? 0 : bundleContext.getBundle().getBundleId());
Object hook;
try {
hook = new RegionBundleCollisionHook(this, this.threadLocal);
diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/equinox/internal/region/hook/RegionBundleEventHook.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/equinox/internal/region/hook/RegionBundleEventHook.java
index 3edb511..8b27915 100644
--- a/bundles/org.eclipse.equinox.region/src/org/eclipse/equinox/internal/region/hook/RegionBundleEventHook.java
+++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/equinox/internal/region/hook/RegionBundleEventHook.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2011 VMware Inc.
+ * 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
@@ -16,7 +16,6 @@
import org.eclipse.equinox.region.RegionDigraph;
import org.osgi.framework.*;
import org.osgi.framework.hooks.bundle.EventHook;
-import org.osgi.framework.hooks.bundle.FindHook;
/**
* {@link RegionBundleEventHook} manages the visibility of bundle events across regions according to the
@@ -33,14 +32,14 @@
private final RegionDigraph regionDigraph;
- private final FindHook bundleFindHook;
-
private final ThreadLocal<Region> threadLocal;
- public RegionBundleEventHook(RegionDigraph regionDigraph, FindHook bundleFindBook, ThreadLocal<Region> threadLocal) {
+ private final long hookImplID;
+
+ public RegionBundleEventHook(RegionDigraph regionDigraph, ThreadLocal<Region> threadLocal, long hookImplID) {
this.regionDigraph = regionDigraph;
- this.bundleFindHook = bundleFindBook;
this.threadLocal = threadLocal;
+ this.hookImplID = hookImplID;
}
/**
@@ -52,10 +51,35 @@
if (event.getType() == BundleEvent.INSTALLED) {
bundleInstalled(eventBundle, event.getOrigin());
}
+ Map<Region, Boolean> regionAccess = new HashMap<Region, Boolean>();
Iterator<BundleContext> i = contexts.iterator();
while (i.hasNext()) {
- if (!find(i.next(), eventBundle)) {
+ Bundle bundle = RegionBundleFindHook.getBundle(i.next());
+ if (bundle == null) {
+ // no bundle for context remove access from it
i.remove();
+ continue;
+ }
+
+ long bundleID = bundle.getBundleId();
+ if (bundleID == 0 || bundleID == hookImplID) {
+ // The system bundle and the hook impl bundle can see all bundles
+ continue;
+ }
+ Region region = regionDigraph.getRegion(bundle);
+ if (region == null) {
+ // no region for context remove access from it
+ i.remove();
+ } else {
+ Boolean accessible = regionAccess.get(region);
+ if (accessible == null) {
+ // we have not checked this region's access do it now
+ accessible = isAccessible(region, eventBundle);
+ regionAccess.put(region, accessible);
+ }
+ if (!accessible) {
+ i.remove();
+ }
}
}
if (event.getType() == BundleEvent.UNINSTALLED) {
@@ -63,10 +87,10 @@
}
}
- private boolean find(BundleContext finderBundleContext, Bundle candidateBundle) {
+ private boolean isAccessible(Region region, Bundle candidateBundle) {
Collection<Bundle> candidates = new ArrayList<Bundle>(1);
candidates.add(candidateBundle);
- this.bundleFindHook.find(finderBundleContext, candidates);
+ RegionBundleFindHook.find(region, candidates);
return !candidates.isEmpty();
}
diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/equinox/internal/region/hook/RegionBundleFindHook.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/equinox/internal/region/hook/RegionBundleFindHook.java
index 6c41f73..9cba364 100644
--- a/bundles/org.eclipse.equinox.region/src/org/eclipse/equinox/internal/region/hook/RegionBundleFindHook.java
+++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/equinox/internal/region/hook/RegionBundleFindHook.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2013 VMware Inc.
+ * Copyright (c) 2013, 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
@@ -53,6 +53,10 @@
}
Region finderRegion = this.regionDigraph.getRegion(finderBundle);
+ RegionBundleFindHook.find(finderRegion, bundles);
+ }
+
+ static void find(Region finderRegion, Collection<Bundle> bundles) {
if (finderRegion == null) {
bundles.clear();
return;
@@ -65,7 +69,7 @@
bundles.retainAll(allowed);
}
- class Visitor extends RegionDigraphVisitorBase<Bundle> {
+ static class Visitor extends RegionDigraphVisitorBase<Bundle> {
Visitor(Collection<Bundle> candidates) {
super(candidates);