blob: 9cba36445fa1edc287df3bcc68be8a1462cc892c [file] [log] [blame]
/*******************************************************************************
* 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* VMware Inc. - initial contribution
*******************************************************************************/
package org.eclipse.equinox.internal.region.hook;
import java.util.Collection;
import java.util.HashMap;
import org.eclipse.equinox.region.*;
import org.osgi.framework.*;
import org.osgi.framework.hooks.bundle.FindHook;
/**
* {@link RegionBundleFindHook} manages the visibility of bundles across regions according to the {@link RegionDigraph}.
* <p />
*
* <strong>Concurrent Semantics</strong><br />
* Thread safe.
*/
public final class RegionBundleFindHook implements FindHook {
private final RegionDigraph regionDigraph;
private final long hookImplID;
public RegionBundleFindHook(RegionDigraph regionDigraph, long hookImplID) {
this.regionDigraph = regionDigraph;
this.hookImplID = hookImplID;
}
/**
* {@inheritDoc}
*/
@Override
public void find(BundleContext context, Collection<Bundle> bundles) {
Bundle finderBundle = getBundle(context);
if (finderBundle == null) {
// invalid finder bundle; clear out result
bundles.clear();
return;
}
long bundleID = finderBundle.getBundleId();
if (bundleID == 0 || bundleID == hookImplID) {
// The system bundle and the hook impl bundle can see all bundles
return;
}
Region finderRegion = this.regionDigraph.getRegion(finderBundle);
RegionBundleFindHook.find(finderRegion, bundles);
}
static void find(Region finderRegion, Collection<Bundle> bundles) {
if (finderRegion == null) {
bundles.clear();
return;
}
Visitor visitor = new Visitor(bundles);
finderRegion.visitSubgraph(visitor);
Collection<Bundle> allowed = visitor.getAllowed();
bundles.retainAll(allowed);
}
static class Visitor extends RegionDigraphVisitorBase<Bundle> {
Visitor(Collection<Bundle> candidates) {
super(candidates);
}
/**
* {@inheritDoc}
*/
@Override
protected boolean contains(Region region, Bundle candidate) {
return region.contains(candidate);
}
/**
* {@inheritDoc}
*/
@Override
protected boolean isAllowed(Bundle candidate, RegionFilter filter) {
return filter.isAllowed(candidate) || isLifecycleAllowed(filter, candidate);
}
private boolean isLifecycleAllowed(RegionFilter filter, Bundle bundle) {
HashMap<String, Object> attrs = new HashMap<String, Object>(4);
String bsn = bundle.getSymbolicName();
if (bsn != null) {
attrs.put(RegionFilter.VISIBLE_BUNDLE_NAMESPACE, bsn);
attrs.put(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, bsn);
}
attrs.put(org.osgi.framework.Constants.BUNDLE_VERSION_ATTRIBUTE, bundle.getVersion());
return filter.isAllowed(RegionFilter.VISIBLE_BUNDLE_LIFECYCLE_NAMESPACE, attrs);
}
}
static Bundle getBundle(BundleContext context) {
try {
return context.getBundle();
} catch (IllegalStateException e) {
// happens if the context is invalid
return null;
}
}
}