in src/main/java/org/apache/sling/feature/apiregions/impl/ResolverHookImpl.java [61:201]
public void filterMatches(BundleRequirement requirement, Collection<BundleCapability> candidates) {
// Filtering is only on package resolution. Any other kind of resolution is not limited
if (!PackageNamespace.PACKAGE_NAMESPACE.equals(requirement.getNamespace()))
return;
if (candidates.isEmpty())
return;
Object pkg = candidates.iterator().next().getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE);
if (!(pkg instanceof String)) {
return;
}
String packageName = (String) pkg;
Bundle reqBundle = requirement.getRevision().getBundle();
long reqBundleID = reqBundle.getBundleId();
Set<String> bareReqRegions = null; // Null means: not opting into API Regions
Set<String> reqFeatures = getFeaturesForBundle(reqBundle);
for (String feature : reqFeatures) {
List<String> fr = this.configuration.getFeatureRegionMap().get(feature);
if (fr != null) {
if (bareReqRegions == null)
bareReqRegions = new HashSet<>();
bareReqRegions.addAll(fr);
}
}
Set<String> reqRegions = new HashSet<>(this.configuration.getDefaultRegions());
if (bareReqRegions != null)
reqRegions.addAll(bareReqRegions);
Map<BundleCapability, String> coveredCaps = new HashMap<>();
Map<BundleCapability, String> bcFeatureMap = new HashMap<>();
nextCapability:
for (BundleCapability bc : candidates) {
BundleRevision rev = bc.getRevision();
Bundle capBundle = rev.getBundle();
long capBundleID = capBundle.getBundleId();
if (capBundleID == 0) {
// always allow capability from the system bundle
coveredCaps.put(bc, null); // null value means same bundle, same feature or system bundle
continue nextCapability;
}
if (capBundleID == reqBundleID) {
// always allow capability from same bundle
// Here we cover the case where the bundle is not in any feature which means that the package is in the 'global' region,
// however if the bundle is in a feature then it could be marked as more specific, with a 'null value', which may
// happen below.
coveredCaps.put(bc, RegionConstants.GLOBAL_REGION);
// note: don't continue to nextCapability here, this one may be overwritten later...
}
Set<String> capFeatures = getFeaturesForBundle(capBundle);
if (capFeatures.isEmpty()) {
// Capability is not in any feature, everyone can access
coveredCaps.put(bc, RegionConstants.GLOBAL_REGION);
continue nextCapability;
}
for (String capFeat : capFeatures) {
if (reqFeatures.contains(capFeat)) {
// Within a single feature everything can wire to everything else
// null value means same bundle, same feature or system bundle, but if exported into global region, use 'global' instead
coveredCaps.put(bc, isInGlobalRegion(packageName, capFeat) ? RegionConstants.GLOBAL_REGION : null);
continue nextCapability;
}
List<String> capRegions = this.configuration.getFeatureRegionMap().get(capFeat);
if (capRegions == null || capRegions.size() == 0) {
// If the feature hosting the capability has no regions defined, everyone can access
coveredCaps.put(bc, RegionConstants.GLOBAL_REGION);
continue nextCapability;
}
bcFeatureMap.put(bc, capFeat);
List<String> sharedRegions = new ArrayList<>(getRegionsAndAncestors(reqRegions));
sharedRegions.retainAll(capRegions);
// Look at specific regions first as they take precedence over the global region
for (String region : sharedRegions) {
Set<String> regionPackages = this.configuration.getRegionPackageMap().get(region);
if (regionPackages != null && regionPackages.contains(packageName)) {
// If the export is in a region that the feature is also in, then allow
coveredCaps.put(bc, region);
continue nextCapability;
}
}
// Now check the global region
Set<String> globalPackages = this.configuration.getRegionPackageMap().get(RegionConstants.GLOBAL_REGION);
if (globalPackages != null && globalPackages.contains(packageName)) {
// If the export is in the global region everyone can access
coveredCaps.put(bc, RegionConstants.GLOBAL_REGION);
continue nextCapability;
}
}
}
pruneCoveredCaps(bareReqRegions, coveredCaps);
List<BundleCapability> removedCandidates = new ArrayList<>(candidates);
// Remove any capabilities that are not covered
candidates.retainAll(coveredCaps.keySet());
Level logLevel;
if (candidates.isEmpty()) {
logLevel = Level.WARNING;
} else {
logLevel = Level.INFO;
}
removedCandidates.removeAll(candidates);
if (!removedCandidates.isEmpty()) {
StringBuilder sb = new StringBuilder();
boolean first = true;
for (BundleCapability bc : removedCandidates) {
if (first)
first = false;
else
sb.append(", ");
String capFeat = bcFeatureMap.get(bc);
sb.append(bc.toString());
sb.append("[Regions: ");
sb.append(getRegionsForPackage(packageName, capFeat));
sb.append(", Feature: ");
sb.append(capFeat);
sb.append("]");
}
Activator.LOG.log(logLevel,
"API-Regions removed candidates {0} for requirement {1} as the requirement is in the following regions: {2} and in feature: {3}",
new Object[] {sb, requirement, reqRegions, reqFeatures});
}
}