public void filterMatches()

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});
        }
    }