in src/main/java/org/apache/sling/feature/analyser/task/impl/CheckRequirementsCapabilities.java [57:176]
public void execute(AnalyserTaskContext ctx) throws Exception {
final SortedMap<Integer, List<Descriptor>> artifactsMap = new TreeMap<>();
for (final BundleDescriptor bi : ctx.getFeatureDescriptor().getBundleDescriptors()) {
List<Descriptor> list = getDescriptorList(bi.getArtifact().getStartOrder(), artifactsMap);
list.add(bi);
}
if (!ctx.getFeatureDescriptor().getArtifactDescriptors().isEmpty()) {
artifactsMap.put(
(artifactsMap.isEmpty() ? 0 : artifactsMap.lastKey()) + 1,
new ArrayList<>(ctx.getFeatureDescriptor().getArtifactDescriptors()));
}
String featureMavenID = ctx.getFeature().getId().toMvnId();
// Add descriptor for feature capabilties. These are added at start level 0
Descriptor featureCaps = new ReqCapDescriptor(featureMavenID);
featureCaps.getCapabilities().addAll(ctx.getFeature().getCapabilities());
getDescriptorList(0, artifactsMap).add(featureCaps);
// Add descriptor for feature requirements. These are added at the highest start level found
Descriptor featureReqs = new ReqCapDescriptor(featureMavenID);
featureReqs.getRequirements().addAll(ctx.getFeature().getRequirements());
Integer highestStartLevel = artifactsMap.lastKey();
getDescriptorList(highestStartLevel, artifactsMap).add(featureReqs);
// add system artifact
final List<Descriptor> artifacts = new ArrayList<>();
if (ctx.getFrameworkDescriptor() != null) {
artifacts.add(ctx.getFrameworkDescriptor());
}
boolean errorReported = false;
for (final Map.Entry<Integer, List<Descriptor>> entry : artifactsMap.entrySet()) {
// first add all providing artifacts
for (final Descriptor info : entry.getValue()) {
if (info.getCapabilities() != null) {
artifacts.add(info);
}
}
// check requiring artifacts
for (final Descriptor info : entry.getValue()) {
if (info.getRequirements() != null) {
for (Requirement requirement : info.getRequirements()) {
String ns = requirement.getNamespace();
// Package namespace is handled by the CheckBundleExportsImports analyzer.
// Service namespace is special - we don't provide errors or warnings in this case
if (!BundleRevision.PACKAGE_NAMESPACE.equals(ns)
&& !ServiceNamespace.SERVICE_NAMESPACE.equals(ns)) {
List<Descriptor> candidates = getCandidates(artifacts, requirement);
String cardinality = requirement
.getDirectives()
.getOrDefault(
Namespace.REQUIREMENT_CARDINALITY_DIRECTIVE, Namespace.CARDINALITY_SINGLE);
if (candidates.isEmpty()) {
if (!RequirementImpl.isOptional(requirement)) {
String message = String.format(
format,
info.getName(),
requirement.toString(),
entry.getKey(),
"no artifact is providing a matching capability in this start level.");
if (info instanceof ArtifactDescriptor) {
ctx.reportArtifactError(
((ArtifactDescriptor) info)
.getArtifact()
.getId(),
message);
} else {
ctx.reportError(message);
}
errorReported = true;
} else {
String message = String.format(
format,
info.getName(),
requirement.toString(),
entry.getKey(),
"while the requirement is optional no artifact is providing a matching capability in this start level.");
if (info instanceof ArtifactDescriptor) {
ctx.reportArtifactWarning(
((ArtifactDescriptor) info)
.getArtifact()
.getId(),
message);
} else {
ctx.reportWarning(message);
}
}
} else if (candidates.size() > 1
&& Objects.equals(cardinality, Namespace.CARDINALITY_SINGLE)) {
String message = String.format(
format,
info.getName(),
requirement.toString(),
entry.getKey(),
"there is more than one matching capability in this start level: "
+ candidates);
if (info instanceof ArtifactDescriptor) {
ctx.reportArtifactWarning(
((ArtifactDescriptor) info)
.getArtifact()
.getId(),
message);
} else {
ctx.reportWarning(message);
}
}
}
}
}
}
}
if (errorReported && ctx.getFeature().isComplete()) {
ctx.reportError(
ctx.getFeature().getId().toMvnId() + " is marked as 'complete' but has unsatisfied requirements.");
}
}