Bug 477071 - [region] should filter resolution of bundles that are unknown to region
diff --git a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/internal/tests/hook/RegionResolverHookTests.java b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/internal/tests/hook/RegionResolverHookTests.java
index 41fbe52..e6a0bf6 100644
--- a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/internal/tests/hook/RegionResolverHookTests.java
+++ b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/internal/tests/hook/RegionResolverHookTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2013 VMware Inc.
+ * Copyright (c) 2012, 2015 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
@@ -111,6 +111,13 @@
 	}
 
 	@Test
+	public void testNoRegionResolvable() {
+		Collection<BundleRevision> resolvable = new ArrayList<BundleRevision>(Collections.singleton(new StubBundleRevision(bundle(BUNDLE_X))));
+		this.resolverHook.filterResolvable(resolvable);
+		assertTrue("Resolvable is not empty" + resolvable, resolvable.isEmpty());
+	}
+
+	@Test
 	public void testResolveInDisconnectedRegion() {
 		this.candidates.add(packageCapability(BUNDLE_B, PACKAGE_B));
 		this.resolverHook.filterMatches(bundleRequirement(BUNDLE_A), this.candidates);
@@ -317,7 +324,6 @@
 
 	@Test
 	public void testUnimplementedMethods() {
-		this.resolverHook.filterResolvable(null);
 		this.resolverHook.end();
 	}
 
diff --git a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/tests/system/RegionSystemTests.java b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/tests/system/RegionSystemTests.java
index e021466..e8abd8a 100644
--- a/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/tests/system/RegionSystemTests.java
+++ b/bundles/org.eclipse.equinox.region.tests/src/org/eclipse/equinox/region/tests/system/RegionSystemTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011, 2013 IBM Corporation and others.
+ * Copyright (c) 2011, 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
@@ -15,10 +15,12 @@
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.*;
+import java.util.concurrent.CopyOnWriteArrayList;
 import javax.management.*;
 import org.eclipse.equinox.region.*;
 import org.osgi.framework.*;
 import org.osgi.framework.hooks.bundle.CollisionHook;
+import org.osgi.framework.hooks.bundle.EventHook;
 import org.osgi.framework.hooks.resolver.ResolverHook;
 import org.osgi.framework.hooks.resolver.ResolverHookFactory;
 import org.osgi.framework.wiring.*;
@@ -738,4 +740,44 @@
 		}
 
 	}
+
+	public void testHigherRankedEventHook() throws BundleException {
+		final List<BundleEvent> events = new CopyOnWriteArrayList<BundleEvent>();
+		SynchronousBundleListener listener = new SynchronousBundleListener() {
+			@Override
+			public void bundleChanged(BundleEvent event) {
+				events.add(event);
+			}
+		};
+		getContext().addBundleListener(listener);
+		// register a higher ranked bundle EventHook that causes a bundle to resolve while processing INSTALLED events
+		ServiceRegistration<EventHook> bundleEventHook = getContext().registerService(EventHook.class, new EventHook() {
+			@Override
+			public void event(BundleEvent event, Collection<BundleContext> contexts) {
+				// force resolution if event is INSTALLED
+				if (event.getType() == BundleEvent.INSTALLED) {
+					getContext().getBundle(Constants.SYSTEM_BUNDLE_LOCATION).adapt(FrameworkWiring.class).resolveBundles(Collections.singleton(event.getBundle()));
+				}
+			}
+		}, new Hashtable<String, Object>(Collections.singletonMap(Constants.SERVICE_RANKING, Integer.MAX_VALUE)));
+		Bundle b = null;
+		try {
+			// install a bundle with no dependencies
+			b = bundleInstaller.installBundle(CP1);
+			b.start();
+		} finally {
+			getContext().removeBundleListener(listener);
+			bundleEventHook.unregister();
+		}
+
+		for (int eventType : new int[] {BundleEvent.INSTALLED, BundleEvent.RESOLVED, BundleEvent.STARTING, BundleEvent.STARTED}) {
+			if (events.isEmpty()) {
+				fail("No events left, expecting event: " + eventType);
+			}
+			BundleEvent event = events.remove(0);
+			assertEquals("Wrong event type.", eventType, event.getType());
+			assertEquals("Wrong bundle.", b, event.getBundle());
+		}
+	}
+
 }
diff --git a/bundles/org.eclipse.equinox.region/src/org/eclipse/equinox/internal/region/hook/RegionResolverHook.java b/bundles/org.eclipse.equinox.region/src/org/eclipse/equinox/internal/region/hook/RegionResolverHook.java
index 42e1126..e1d94b3 100644
--- a/bundles/org.eclipse.equinox.region/src/org/eclipse/equinox/internal/region/hook/RegionResolverHook.java
+++ b/bundles/org.eclipse.equinox.region/src/org/eclipse/equinox/internal/region/hook/RegionResolverHook.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011, 2013 VMware Inc.
+ * Copyright (c) 2011, 2015 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
@@ -118,8 +118,12 @@
 
 	@Override
 	public void filterResolvable(Collection<BundleRevision> candidates) {
-		// do nothing
-		// may want to consider only allowing candidates contained in the region of the trigger revisions?
+		// filter any revisions that have no region
+		for (Iterator<BundleRevision> iCandidates = candidates.iterator(); iCandidates.hasNext();) {
+			if (getRegion(iCandidates.next()) == null) {
+				iCandidates.remove();
+			}
+		}
 	}
 
 	@Override