This is an automated email from the ASF dual-hosted git repository. pauls pushed a commit to branch issues/SLING-9823_SLING-9822_SLING-9805 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-analyser.git
commit 47fb1cce82597ce81522b19b00f36cb5d928b388 Author: Karl Pauls <[email protected]> AuthorDate: Tue Oct 27 09:20:19 2020 +0100 Rework the analyser to report more context and improve the meta data caching extension. * SLING-9823 - Make analyzers report more context about issues and make it possible to filter reports. * SLING-9822 - Make artifact retrieval lazy for cached artifacts. * SLING-9805 - Add a method to create the metadata cache extension. --- .../apache/sling/feature/analyser/Analyser.java | 79 ++++++++++-- .../sling/feature/analyser/AnalyserResult.java | 96 +++++++++++++- .../extensions/AnalyserMetaDataExtension.java | 142 +++++++++++++++++++++ .../feature/analyser/task/AnalyserTaskContext.java | 39 +++++- .../task/impl/CheckApisJarsProperties.java | 21 ++- .../task/impl/CheckBundleExportsImports.java | 8 +- .../analyser/task/impl/CheckBundleNativeCode.java | 2 +- .../analyser/task/impl/CheckBundlesForConnect.java | 11 +- .../task/impl/CheckBundlesForInitialContent.java | 2 +- .../task/impl/CheckBundlesForResources.java | 2 +- .../impl/CheckContentPackageForInstallables.java | 8 +- .../impl/CheckContentPackagesDependencies.java | 24 ++-- .../feature/analyser/task/impl/CheckRepoinit.java | 4 +- .../task/impl/CheckRequirementsCapabilities.java | 8 +- .../analyser/task/impl/CheckUnusedBundles.java | 4 +- .../sling/feature/analyser/task/package-info.java | 2 +- .../sling/feature/scanner/ArtifactDescriptor.java | 2 +- .../org/apache/sling/feature/scanner/Scanner.java | 47 +++---- .../feature/scanner/impl/BundleDescriptorImpl.java | 31 ++++- .../scanner/impl/ContentPackageScanner.java | 21 +-- .../impl/ContentPackagesExtensionScanner.java | 28 +++- .../extensions/AnalyserMetaDataExtensionTest.java | 61 +++++++++ ...iderTest.java => AnalyserTaskProviderTest.java} | 2 +- .../task/impl/CheckApisJarsPropertiesTest.java | 24 ++++ .../task/impl/CheckBundleExportsImportsTest.java | 8 +- .../task/impl/CheckBundleNativeCodeTest.java | 2 +- .../analyser/task/impl/CheckRepoinitTest.java | 20 +++ .../impl/CheckRequirementsCapabilitiesTest.java | 2 +- 28 files changed, 584 insertions(+), 116 deletions(-) diff --git a/src/main/java/org/apache/sling/feature/analyser/Analyser.java b/src/main/java/org/apache/sling/feature/analyser/Analyser.java index 82bcd1b..5c06fc2 100644 --- a/src/main/java/org/apache/sling/feature/analyser/Analyser.java +++ b/src/main/java/org/apache/sling/feature/analyser/Analyser.java @@ -32,6 +32,7 @@ import java.util.Set; import org.apache.sling.feature.ArtifactId; import org.apache.sling.feature.ExecutionEnvironmentExtension; import org.apache.sling.feature.Feature; +import org.apache.sling.feature.analyser.extensions.AnalyserMetaDataExtension; import org.apache.sling.feature.analyser.task.AnalyserTask; import org.apache.sling.feature.analyser.task.AnalyserTaskContext; import org.apache.sling.feature.builder.FeatureProvider; @@ -198,8 +199,15 @@ public class Analyser { } final BundleDescriptor fwkDesc = bd; - final List<String> warnings = new ArrayList<>(); - final List<String> errors = new ArrayList<>(); + final List<AnalyserResult.GlobalReport> globalWarnings = new ArrayList<>(); + final List<AnalyserResult.ArtifactReport> artifactWarnings = new ArrayList<>(); + final List<AnalyserResult.ExtensionReport> extensionWarnings = new ArrayList<>(); + + final List<AnalyserResult.GlobalReport> globalErrors = new ArrayList<>(); + final List<AnalyserResult.ArtifactReport> artifactErrors = new ArrayList<>(); + final List<AnalyserResult.ExtensionReport> extensionErrors = new ArrayList<>(); + + AnalyserMetaDataExtension analyserMetaDataExtension = AnalyserMetaDataExtension.getAnalyserMetaDataExtension(feature); // execute analyser tasks for (final AnalyserTask task : tasks) { @@ -236,29 +244,80 @@ public class Analyser { @Override public void reportWarning(final String message) { - warnings.add(message); + if (analyserMetaDataExtension != null && analyserMetaDataExtension.reportWarning(feature.getId())) { + globalWarnings.add(new AnalyserResult.GlobalReport(message)); + } + } + + @Override + public void reportArtifactWarning(ArtifactId artifactId, String message) { + if (analyserMetaDataExtension != null && analyserMetaDataExtension.reportWarning(artifactId) && analyserMetaDataExtension.reportWarning(feature.getId())) { + artifactWarnings.add(new AnalyserResult.ArtifactReport(artifactId, message)); + } + } + + @Override + public void reportArtifactError(ArtifactId artifactId, String message) { + if (analyserMetaDataExtension != null && analyserMetaDataExtension.reportError(artifactId)&& analyserMetaDataExtension.reportError(feature.getId())) { + artifactErrors.add(new AnalyserResult.ArtifactReport(artifactId, message)); + } + } + + @Override + public void reportExtensionWarning(String extension, String message) { + if (analyserMetaDataExtension != null && analyserMetaDataExtension.reportWarning(feature.getId())) { + extensionWarnings.add(new AnalyserResult.ExtensionReport(extension, message)); + } + } + + @Override + public void reportExtensionError(String extension, String message) { + if (analyserMetaDataExtension != null && analyserMetaDataExtension.reportError(feature.getId())) { + extensionErrors.add(new AnalyserResult.ExtensionReport(extension, message)); + } } @Override public void reportError(final String message) { - errors.add(message); + if (analyserMetaDataExtension != null && analyserMetaDataExtension.reportError(feature.getId())) { + globalErrors.add(new AnalyserResult.GlobalReport(message)); + } } }); } - logger.info("Analyzing feature '" + feature.getId() + "' finished : " + warnings.size() + " warnings, " - + errors.size() + " errors."); + logger.info("Analyzing feature '" + feature.getId() + "' finished : " + globalWarnings.size() + artifactWarnings.size() + extensionWarnings.size() + " warnings, " + + globalErrors.size() + artifactErrors.size() + extensionErrors.size() + " errors."); return new AnalyserResult() { + @Override + public List<GlobalReport> getGlobalWarnings() { + return globalWarnings; + } + + @Override + public List<ArtifactReport> getArtifactWarnings() { + return artifactWarnings; + } + + @Override + public List<ExtensionReport> getExtensionWarnings() { + return extensionWarnings; + } + + @Override + public List<GlobalReport> getGlobalErrors() { + return globalErrors; + } @Override - public List<String> getWarnings() { - return warnings; + public List<ArtifactReport> getArtifactErrors() { + return artifactErrors; } @Override - public List<String> getErrors() { - return errors; + public List<ExtensionReport> getExtensionErrors() { + return extensionErrors; } @Override diff --git a/src/main/java/org/apache/sling/feature/analyser/AnalyserResult.java b/src/main/java/org/apache/sling/feature/analyser/AnalyserResult.java index 717eedf..5ab04c4 100644 --- a/src/main/java/org/apache/sling/feature/analyser/AnalyserResult.java +++ b/src/main/java/org/apache/sling/feature/analyser/AnalyserResult.java @@ -16,29 +16,117 @@ */ package org.apache.sling.feature.analyser; -import java.util.List; - +import org.apache.sling.feature.ArtifactId; import org.apache.sling.feature.scanner.BundleDescriptor; import org.apache.sling.feature.scanner.FeatureDescriptor; import org.osgi.annotation.versioning.ProviderType; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + /** * The result returned by the analyser */ @ProviderType public interface AnalyserResult { + class Report<T> { + private final T key; + private final String value; + Report(T key, String value) { + this.key = key; + this.value = value; + } + T getKey() { + return key; + } + String getValue() { + return value; + } + } + + class ArtifactReport extends Report<ArtifactId> { + ArtifactReport(ArtifactId key, String value) { + super(key, value); + } + } + + class ExtensionReport extends Report<String> { + ExtensionReport(String key, String value) { + super(key, value); + } + } + + class GlobalReport extends Report<Void> { + + GlobalReport(String value) { + super(null, value); + } + } + /** * List of warnings. Warnings can be used to improve the feature. * @return A list of warnings might be empty. + * @deprecated - use {@link #getGlobalWarnings()} ()}, {@link #getArtifactWarnings()} ()}, and {@link #getExtensionWarnings()} ()} instead. + */ + default List<String> getWarnings() { + return Stream.of(getGlobalWarnings().stream().map(Report::getValue), + getArtifactWarnings().stream().map(report -> report.getKey() + ": " + report.getValue()), + getExtensionWarnings().stream().map(report -> report.getKey() + ": " + report.getValue())) + .flatMap(Function.identity()) + .collect(Collectors.toList()); + } + + /** + * List of global warnings. Warnings can be used to improve the feature. + * @return A list of warnings might be empty. + */ + List<GlobalReport> getGlobalWarnings(); + + /** + * List of warnings for artifact ids. Warnings can be used to improve the feature. + * @return A list of warnings might be empty. */ - List<String> getWarnings(); + List<ArtifactReport> getArtifactWarnings(); + + /** + * List of warnings for extension names. Warnings can be used to improve the feature. + * @return A list of warnings might be empty. + */ + List<ExtensionReport> getExtensionWarnings(); /** * List of errors. Errors should be fixed in the feature * @return A list of errors might be empty + * @deprecated - use {@link #getGlobalErrors()}, {@link #getArtifactErrors()}, and {@link #getExtensionErrors()} instead. + */ + default List<String> getErrors() { + return Stream.of(getGlobalErrors().stream().map(Report::getValue), + getArtifactErrors().stream().map(report -> report.getKey() + ": " + report.getValue()), + getExtensionErrors().stream().map(report -> report.getKey() + ": " + report.getValue())) + .flatMap(Function.identity()) + .collect(Collectors.toList()); + } + + /** + * List of global errors. Errors should be fixed in the feature + * @return A list of errors might be empty + */ + List<GlobalReport> getGlobalErrors(); + + /** + * List of errors for artifact ids. Errors should be fixed in the feature + * @return A list of errors might be empty + */ + List<ArtifactReport> getArtifactErrors(); + + /** + * List of errors for extension names. Errors should be fixed in the feature + * @return A list of errors might be empty */ - List<String> getErrors(); + List<ExtensionReport> getExtensionErrors(); /** * Return the feature descriptor created during scanning diff --git a/src/main/java/org/apache/sling/feature/analyser/extensions/AnalyserMetaDataExtension.java b/src/main/java/org/apache/sling/feature/analyser/extensions/AnalyserMetaDataExtension.java new file mode 100644 index 0000000..9aca541 --- /dev/null +++ b/src/main/java/org/apache/sling/feature/analyser/extensions/AnalyserMetaDataExtension.java @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sling.feature.analyser.extensions; + +import org.apache.sling.feature.ArtifactId; +import org.apache.sling.feature.Extension; +import org.apache.sling.feature.ExtensionType; +import org.apache.sling.feature.Feature; +import org.apache.sling.feature.scanner.BundleDescriptor; + +import javax.json.Json; +import javax.json.JsonObject; +import javax.json.JsonObjectBuilder; +import javax.json.JsonValue; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.stream.Stream; + +public class AnalyserMetaDataExtension { + public static final String EXTENSION_NAME = "analyser-metadata"; + + private final Map<ArtifactId, Map<String, String>> manifests = new HashMap<>(); + private final Map<ArtifactId, Boolean> reportWarnings = new HashMap<>(); + private final Map<ArtifactId, Boolean> reportErrors = new HashMap<>(); + + public static AnalyserMetaDataExtension getAnalyserMetaDataExtension(Feature feature) { + Extension ext = feature == null ? null : feature.getExtensions().getByName(EXTENSION_NAME); + return getAnalyserMetaDataExtension(ext); + } + + public static AnalyserMetaDataExtension getAnalyserMetaDataExtension(Extension ext) { + if (ext == null) { + return null; + } else if (ext.getType() != ExtensionType.JSON) { + throw new IllegalArgumentException("Extension " + ext.getName() + " must have JSON type"); + } else { + return new AnalyserMetaDataExtension(ext.getJSONStructure().asJsonObject()); + } + } + + private AnalyserMetaDataExtension(JsonObject json) { + for (Map.Entry<String, JsonValue> entry : json.entrySet()) { + ArtifactId id = ArtifactId.fromMvnId(entry.getKey()); + JsonObject headers = entry.getValue().asJsonObject(); + if (headers.containsKey("manifest")) { + Map<String, String> manifest = new LinkedHashMap<>(); + JsonObject manifestHeaders = headers.getJsonObject("manifest"); + for (String name : manifestHeaders.keySet()) { + manifest.put(name, manifestHeaders.getString(name)); + } + this.manifests.put(id, manifest); + } + if (headers.containsKey("report")) { + JsonObject report = headers.getJsonObject("report"); + if (report.containsKey("warning")) { + reportWarnings.put(id, report.getBoolean("warning")); + } + if (report.containsKey("error")) { + reportErrors.put(id, report.getBoolean("error")); + } + } + } + } + + public static boolean isAnalyserMetaDataExtension(Extension ext) { + return ext != null && ext.getName().equals(EXTENSION_NAME) && ext.getType() == ExtensionType.JSON; + } + + public Map<String, String> getManifest(ArtifactId artifactId) { + return this.manifests.get(artifactId); + } + + public boolean reportWarning(ArtifactId artifactId) { + return !this.reportWarnings.containsKey(artifactId) || this.reportWarnings.get(artifactId); + } + + public boolean reportError(ArtifactId artifactId) { + return !this.reportErrors.containsKey(artifactId) || this.reportErrors.get(artifactId); + } + + public Extension toExtension(Extension extension) { + if (isAnalyserMetaDataExtension(extension)) { + JsonObjectBuilder builder = Json.createObjectBuilder(extension.getJSONStructure().asJsonObject()); + Stream.concat(Stream.concat(manifests.keySet().stream(), reportErrors.keySet().stream()), reportWarnings.keySet().stream()).distinct().forEachOrdered( + id -> { + JsonObjectBuilder metadata = Json.createObjectBuilder(); + if (manifests.containsKey(id)) { + JsonObjectBuilder manifest = Json.createObjectBuilder(); + manifests.get(id).forEach(manifest::add); + metadata.add("manifest", manifest); + } + if (reportErrors.containsKey(id) || reportWarnings.containsKey(id)) { + JsonObjectBuilder report = Json.createObjectBuilder(); + if (reportErrors.containsKey(id)) { + report.add("error", reportErrors.get(id)); + } + if (reportWarnings.containsKey(id)) { + report.add("warning", reportWarnings.get(id)); + } + metadata.add("report", report); + } + builder.add(id.toMvnId(), metadata); + } + ); + extension.setJSONStructure(builder.build()); + } + return extension; + } + + public void add(BundleDescriptor... bundleDescriptors) { + for (BundleDescriptor descriptor : bundleDescriptors) { + Map<String, String> manifest = new LinkedHashMap<>(); + descriptor.getManifest().getMainAttributes().entrySet().stream() + .forEachOrdered(entry -> manifest.put(entry.getKey().toString(), (String) entry.getValue())); + + manifests.put(descriptor.getArtifact().getId(), manifest); + } + } + + public void setReportWarnings(ArtifactId id, boolean enabled) { + reportWarnings.put(id, enabled); + } + + public void setReportErrors(ArtifactId id, boolean enabled) { + reportErrors.put(id, enabled); + } +} diff --git a/src/main/java/org/apache/sling/feature/analyser/task/AnalyserTaskContext.java b/src/main/java/org/apache/sling/feature/analyser/task/AnalyserTaskContext.java index d2043d8..f5cee5c 100644 --- a/src/main/java/org/apache/sling/feature/analyser/task/AnalyserTaskContext.java +++ b/src/main/java/org/apache/sling/feature/analyser/task/AnalyserTaskContext.java @@ -16,6 +16,7 @@ */ package org.apache.sling.feature.analyser.task; +import org.apache.sling.feature.ArtifactId; import org.apache.sling.feature.Feature; import org.apache.sling.feature.builder.FeatureProvider; import org.apache.sling.feature.scanner.BundleDescriptor; @@ -61,16 +62,50 @@ public interface AnalyserTaskContext { /** * This method is invoked by a {@link AnalyserTask} to report - * a warning. + * a global warning. * @param message The message. */ void reportWarning(String message); /** * This method is invoked by a {@link AnalyserTask} to report - * an error. + * an artifact warning. + * @param artifactId the artifactid + * @param message The message. + */ + void reportArtifactWarning(ArtifactId artifactId, String message); + + /** + * This method is invoked by a {@link AnalyserTask} to report + * an artifact error. + * @param artifactId the artifactid + * @param message The message. + */ + void reportArtifactError(ArtifactId artifactId, String message); + + /** + * This method is invoked by a {@link AnalyserTask} to report + * an extension warning. + * @param extension the extension. + * @param message The message. + */ + void reportExtensionWarning(String extension, String message); + + /** + * This method is invoked by a {@link AnalyserTask} to report + * an extension error. + * @param extension the extension. + * @param message The message. + */ + void reportExtensionError(String extension, String message); + + /** + * This method is invoked by a {@link AnalyserTask} to report + * a global error. * @param message The message. */ void reportError(String message); + + } diff --git a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckApisJarsProperties.java b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckApisJarsProperties.java index e1a138e..9a01c03 100644 --- a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckApisJarsProperties.java +++ b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckApisJarsProperties.java @@ -120,7 +120,7 @@ public class CheckApisJarsProperties implements AnalyserTask { final Extension ext = ctx.getFeature().getExtensions().getByName(EXTENSION_NAME); if ( ext != null ) { if ( ext.getType() != ExtensionType.JSON ) { - ctx.reportError("Extension ".concat(EXTENSION_NAME).concat(" is not of type JSON")); + ctx.reportExtensionError(EXTENSION_NAME,"is not of type JSON"); } else { final JsonObject obj = ext.getJSONStructure().asJsonObject(); checkStringType(ctx, obj, PROP_API_VERSION); @@ -146,7 +146,7 @@ public class CheckApisJarsProperties implements AnalyserTask { if ( obj.containsKey(propName) ) { final JsonValue val = obj.get(propName); if ( val.getValueType() != ValueType.STRING ) { - ctx.reportError("Extension ".concat(EXTENSION_NAME).concat(" : property ").concat(propName).concat(" is not of type String")); + ctx.reportExtensionError(EXTENSION_NAME,"property ".concat(propName).concat(" is not of type String")); } } } @@ -155,7 +155,7 @@ public class CheckApisJarsProperties implements AnalyserTask { if ( obj.containsKey(propName) ) { final JsonValue val = obj.get(propName); if ( val.getValueType() != ValueType.ARRAY ) { - ctx.reportError("Extension ".concat(EXTENSION_NAME).concat(" : property ").concat(propName).concat(" is not of type Array")); + ctx.reportExtensionError(EXTENSION_NAME,"property ".concat(propName).concat(" is not of type Array")); } else { boolean hasNonStringValue = false; for(final JsonValue v : val.asJsonArray()) { @@ -164,7 +164,7 @@ public class CheckApisJarsProperties implements AnalyserTask { } } if ( hasNonStringValue ) { - ctx.reportError("Extension ".concat(EXTENSION_NAME).concat(" : array ").concat(propName).concat(" contains non string values")); + ctx.reportExtensionError(EXTENSION_NAME,"array ".concat(propName).concat(" contains non string values")); } } } @@ -183,7 +183,7 @@ public class CheckApisJarsProperties implements AnalyserTask { if ( obj.containsKey(propName) ) { final JsonValue val = obj.get(propName); if ( val.getValueType() != ValueType.OBJECT ) { - ctx.reportError("Extension ".concat(EXTENSION_NAME).concat(" : property ").concat(propName).concat(" is not of type Object")); + ctx.reportExtensionError(EXTENSION_NAME,"property ".concat(propName).concat(" is not of type Object")); } else { boolean hasNonStringValue = false; for(final JsonValue v : val.asJsonObject().values()) { @@ -192,7 +192,7 @@ public class CheckApisJarsProperties implements AnalyserTask { } } if ( hasNonStringValue ) { - ctx.reportError("Extension ".concat(EXTENSION_NAME).concat(" : object ").concat(propName).concat(" contains non string values")); + ctx.reportExtensionError(EXTENSION_NAME,"object ".concat(propName).concat(" contains non string values")); } } } @@ -209,7 +209,7 @@ public class CheckApisJarsProperties implements AnalyserTask { // at the moment we can not validate the availability of the artifact since there is no access to Maven APIs ArtifactId.parse(el); } catch ( IllegalArgumentException e) { - ctx.reportError("Bundle " + a.getId().toMvnId() + " has invalid " + propName + " entry '" + el + "' : " + e.getMessage()); + ctx.reportArtifactError(a.getId()," has invalid " + propName + " entry '" + el + "' : " + e.getMessage()); } }); } @@ -225,7 +225,7 @@ public class CheckApisJarsProperties implements AnalyserTask { try { new URL(v); } catch ( final MalformedURLException mue) { - ctx.reportError("Bundle " + a.getId().toMvnId() + " has invalid javadoc links URL : " + v); + ctx.reportArtifactError(a.getId(),"has invalid javadoc links URL : " + v); } } } @@ -246,9 +246,8 @@ public class CheckApisJarsProperties implements AnalyserTask { count++; } if ( count > 1 ) { - ctx.reportError("Bundle ".concat(artifact.getId().toMvnId()) - .concat(" should either define ") - .concat(SCM_LOCATION).concat(", ") + ctx.reportArtifactError(artifact.getId(), + "should either define ".concat(SCM_LOCATION).concat(", ") .concat(SCM_CLASSIFIER).concat(", or") .concat(SCM_IDS).concat(" - but only one of them.")); } diff --git a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundleExportsImports.java b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundleExportsImports.java index 37ecafa..c93461c 100644 --- a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundleExportsImports.java +++ b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundleExportsImports.java @@ -165,20 +165,20 @@ public class CheckBundleExportsImports implements AnalyserTask { final String key = "Bundle " + entry.getKey().getArtifact().getId().getArtifactId() + ":" + entry.getKey().getArtifact().getId().getVersion(); if ( !entry.getValue().importWithoutVersion.isEmpty() ) { - ctx.reportWarning(key + " is importing package(s) " + getPackageInfo(entry.getValue().importWithoutVersion, false) + " without specifying a version range."); + ctx.reportArtifactWarning(entry.getKey().getArtifact().getId(), " is importing package(s) " + getPackageInfo(entry.getValue().importWithoutVersion, false) + " without specifying a version range."); } if ( !entry.getValue().exportWithoutVersion.isEmpty() ) { - ctx.reportWarning(key + " is exporting package(s) " + getPackageInfo(entry.getValue().importWithoutVersion, false) + " without a version."); + ctx.reportArtifactWarning(entry.getKey().getArtifact().getId(), " is exporting package(s) " + getPackageInfo(entry.getValue().importWithoutVersion, false) + " without a version."); } if ( !entry.getValue().missingExports.isEmpty() ) { - ctx.reportError(key + " is importing package(s) " + getPackageInfo(entry.getValue().missingExports, false) + " in start level " + + ctx.reportArtifactError(entry.getKey().getArtifact().getId(), " is importing package(s) " + getPackageInfo(entry.getValue().missingExports, false) + " in start level " + String.valueOf(entry.getKey().getArtifact().getStartOrder()) + " but no bundle is exporting these for that start level."); errorReported = true; } if ( !entry.getValue().missingExportsWithVersion.isEmpty() ) { - ctx.reportError(key + " is importing package(s) " + ctx.reportArtifactError(entry.getKey().getArtifact().getId(), " is importing package(s) " + getPackageInfo(entry.getValue().missingExportsWithVersion, true) + " in start level " + String.valueOf(entry.getKey().getArtifact().getStartOrder()) + " but no bundle is exporting these for that start level in the required version range."); diff --git a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundleNativeCode.java b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundleNativeCode.java index 5e8fb28..7bd1c47 100644 --- a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundleNativeCode.java +++ b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundleNativeCode.java @@ -44,7 +44,7 @@ public class CheckBundleNativeCode implements AnalyserTask { final String nativeCode = mf.getMainAttributes().getValue(Constants.BUNDLE_NATIVECODE); if ( nativeCode != null ) { - ctx.reportError("Found native code instruction in bundle ".concat(descriptor.getArtifact().getId().toMvnId()).concat(" : ").concat(nativeCode) ); + ctx.reportArtifactError(descriptor.getArtifact().getId(), "Found native code instruction in bundle: ".concat(nativeCode) ); } } } diff --git a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundlesForConnect.java b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundlesForConnect.java index ac82c48..799c243 100644 --- a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundlesForConnect.java +++ b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundlesForConnect.java @@ -55,7 +55,7 @@ public class CheckBundlesForConnect implements AnalyserTask { String[] jars = null; if (cp != null) { jars = cp.split(","); - ctx.reportWarning("Found bundle classpath in " + bd.getArtifact() + " : " + cp); + ctx.reportArtifactWarning(bd.getArtifact().getId(), "Found bundle classpath in : " + cp); } final Set<String> packages = new HashSet<>(); @@ -65,7 +65,7 @@ public class CheckBundlesForConnect implements AnalyserTask { if (entry.getName().endsWith(".class")) { final int lastPos = entry.getName().lastIndexOf('/'); if (lastPos == -1) { - ctx.reportError("Bundle contains classes in the default package: " + bd.getArtifact()); + ctx.reportArtifactError(bd.getArtifact().getId(),"Bundle contains classes in the default package"); } else { packages.add(entry.getName().substring(0, lastPos)); } @@ -78,9 +78,8 @@ public class CheckBundlesForConnect implements AnalyserTask { if (inner.getName().endsWith(".class")) { final int lastPos = inner.getName().lastIndexOf('/'); if (lastPos == -1) { - ctx.reportError( - "Bundle contains (embedded) classes in the default package: " - + bd.getArtifact()); + ctx.reportArtifactError(bd.getArtifact().getId(), + "Bundle contains (embedded) classes in the default package"); } else { packages.add(inner.getName().substring(0, lastPos)); } @@ -93,7 +92,7 @@ public class CheckBundlesForConnect implements AnalyserTask { jis.closeEntry(); } } catch (final IOException ioe) { - ctx.reportError("Unable to scan bundle " + bd.getArtifact() + " : " + ioe.getMessage()); + ctx.reportArtifactError(bd.getArtifact().getId(),"Unable to scan bundle: " + ioe.getMessage()); } for (final String p : packages) { List<Artifact> list = packageMap.get(p); diff --git a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundlesForInitialContent.java b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundlesForInitialContent.java index 5ea7e45..7ddb3d8 100644 --- a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundlesForInitialContent.java +++ b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundlesForInitialContent.java @@ -56,7 +56,7 @@ public class CheckBundlesForInitialContent implements AnalyserTask { final List<String> initialContent = extractInitialContent(info.getManifest()); if ( !initialContent.isEmpty() ) { - ctx.reportWarning("Found initial content in " + info.getArtifact() + " : " + initialContent); + ctx.reportArtifactWarning(info.getArtifact().getId(), "Found initial content : " + initialContent); } } } diff --git a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundlesForResources.java b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundlesForResources.java index a7116d4..044fe53 100644 --- a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundlesForResources.java +++ b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckBundlesForResources.java @@ -55,7 +55,7 @@ public class CheckBundlesForResources implements AnalyserTask { for(final BundleDescriptor info : ctx.getFeatureDescriptor().getBundleDescriptors()) { final List<String> bundleResources = extractBundleResources(info.getManifest()); if ( !bundleResources.isEmpty() ) { - ctx.reportWarning("Found bundle resources in " + info.getArtifact() + " : " + bundleResources); + ctx.reportArtifactWarning(info.getArtifact().getId(), "Found bundle resources : " + bundleResources); } } } diff --git a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckContentPackageForInstallables.java b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckContentPackageForInstallables.java index 12d041a..167b584 100644 --- a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckContentPackageForInstallables.java +++ b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckContentPackageForInstallables.java @@ -53,12 +53,16 @@ public class CheckContentPackageForInstallables implements AnalyserTask { } for (final ContentPackageDescriptor cp : contentPackages) { + if (cp.getArtifactFile() == null) { + ctx.reportArtifactError(cp.getArtifact().getId(), "Content package " + cp.getName() + " is not resolved and can not be checked."); + continue; + } if (!cp.hasEmbeddedArtifacts() || cp.isEmbeddedInContentPackage()) { continue; } - ctx.reportError("Content package " + cp.getName() + " (" + cp.getArtifact().getId().toMvnId() - + " ) contains " + String.valueOf(cp.bundles.size()) + " bundles and " + ctx.reportArtifactError(cp.getArtifact().getId(), "Content package " + cp.getName() + + " contains " + String.valueOf(cp.bundles.size()) + " bundles and " + String.valueOf(cp.configs.size()) + " configurations."); } diff --git a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckContentPackagesDependencies.java b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckContentPackagesDependencies.java index 4091da5..c51de09 100644 --- a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckContentPackagesDependencies.java +++ b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckContentPackagesDependencies.java @@ -74,20 +74,24 @@ public class CheckContentPackagesDependencies implements AnalyserTask { private void onDescriptor(AnalyserTaskContext ctx, ArtifactDescriptor descriptor, Map<PackageId, Dependency[]> dependenciesMap) throws Exception { URL resourceUrl = descriptor.getArtifactFile(); - File artifactFile = IOUtils.getFileFromURL(resourceUrl, true, null); - if (!artifactFile.exists() || !artifactFile.isFile()) { - ctx.reportError("Artifact file " + artifactFile + " does not exist or it is not a file"); - return; - } + if (resourceUrl != null) { + File artifactFile = IOUtils.getFileFromURL(resourceUrl, true, null); + if (!artifactFile.exists() || !artifactFile.isFile()) { + ctx.reportArtifactError(descriptor.getArtifact().getId(), "Artifact file " + artifactFile + " does not exist or it is not a file"); + return; + } - try (VaultPackage vaultPackage = packageManager.open(artifactFile, true)) { - PackageId packageId = vaultPackage.getId(); + try (VaultPackage vaultPackage = packageManager.open(artifactFile, true)) { + PackageId packageId = vaultPackage.getId(); - logger.debug("Collecting " + packageId + " dependencies..."); + logger.debug("Collecting " + packageId + " dependencies..."); - dependenciesMap.put(packageId, vaultPackage.getDependencies()); + dependenciesMap.put(packageId, vaultPackage.getDependencies()); - logger.debug(packageId + " dependencies collected."); + logger.debug(packageId + " dependencies collected."); + } + } else { + ctx.reportArtifactError(descriptor.getArtifact().getId(), "Ignoring " + descriptor.getName() + " as file could not be found"); } } diff --git a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckRepoinit.java b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckRepoinit.java index 2df81a3..ce649ef 100644 --- a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckRepoinit.java +++ b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckRepoinit.java @@ -51,7 +51,7 @@ public class CheckRepoinit implements AnalyserTask { final Extension ext = ctx.getFeature().getExtensions().getByName(Extension.EXTENSION_NAME_REPOINIT); if ( ext != null ) { if ( ext.getType() != ExtensionType.TEXT ) { - ctx.reportError("Repoinit extension must be of type TEXT"); + ctx.reportExtensionError(Extension.EXTENSION_NAME_REPOINIT, "Repoinit extension must be of type TEXT"); } else { check(ctx, "extension", ext.getText()); } @@ -89,7 +89,7 @@ public class CheckRepoinit implements AnalyserTask { try { parser.parse(new StringReader(contents)); } catch ( RepoInitParsingException e) { - ctx.reportError("Parsing error in repoinit from ".concat(id).concat(" : ").concat(e.getMessage())); + ctx.reportExtensionError(Extension.EXTENSION_NAME_REPOINIT, "Parsing error in repoinit from ".concat(id).concat(" : ").concat(e.getMessage())); } } } diff --git a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckRequirementsCapabilities.java b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckRequirementsCapabilities.java index a6821b1..15bc39d 100644 --- a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckRequirementsCapabilities.java +++ b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckRequirementsCapabilities.java @@ -27,6 +27,7 @@ import org.apache.felix.utils.resource.CapabilitySet; import org.apache.felix.utils.resource.RequirementImpl; import org.apache.sling.feature.analyser.task.AnalyserTask; import org.apache.sling.feature.analyser.task.AnalyserTaskContext; +import org.apache.sling.feature.scanner.ArtifactDescriptor; import org.apache.sling.feature.scanner.BundleDescriptor; import org.apache.sling.feature.scanner.Descriptor; import org.osgi.framework.wiring.BundleRevision; @@ -105,7 +106,12 @@ public class CheckRequirementsCapabilities implements AnalyserTask { { if (!RequirementImpl.isOptional(requirement)) { - ctx.reportError(String.format(format, info.getName(), requirement.toString(), entry.getKey(), "no artifact is providing a matching capability in this start level.")); + 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 diff --git a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckUnusedBundles.java b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckUnusedBundles.java index 8b4c767..e2289dc 100644 --- a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckUnusedBundles.java +++ b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckUnusedBundles.java @@ -89,9 +89,9 @@ public class CheckUnusedBundles implements AnalyserTask { if ( exports.size() == info.getExportedPackages().size() ) { if ( !optionalImports.isEmpty() ) { - ctx.reportWarning("Exports from bundle ".concat(info.getArtifact().getId().toMvnId()).concat(" are only imported optionally by other bundles.")); + ctx.reportArtifactWarning(info.getArtifact().getId(), "Exports from bundle are only imported optionally by other bundles."); } else { - ctx.reportWarning("Exports from bundle ".concat(info.getArtifact().getId().toMvnId()).concat(" are not imported by any other bundle.")); + ctx.reportArtifactWarning(info.getArtifact().getId(), "Exports from bundle are not imported by any other bundle."); } } diff --git a/src/main/java/org/apache/sling/feature/analyser/task/package-info.java b/src/main/java/org/apache/sling/feature/analyser/task/package-info.java index 614898f..85a724d 100644 --- a/src/main/java/org/apache/sling/feature/analyser/task/package-info.java +++ b/src/main/java/org/apache/sling/feature/analyser/task/package-info.java @@ -17,7 +17,7 @@ * under the License. */ [email protected]("1.1.0") [email protected]("1.2.0") package org.apache.sling.feature.analyser.task; diff --git a/src/main/java/org/apache/sling/feature/scanner/ArtifactDescriptor.java b/src/main/java/org/apache/sling/feature/scanner/ArtifactDescriptor.java index c717356..43b6df8 100644 --- a/src/main/java/org/apache/sling/feature/scanner/ArtifactDescriptor.java +++ b/src/main/java/org/apache/sling/feature/scanner/ArtifactDescriptor.java @@ -36,7 +36,7 @@ public abstract class ArtifactDescriptor extends Descriptor { /** * Get the artifact file - * @return The artifact file + * @return The artifact file or <code>null</code> if not present. */ public abstract URL getArtifactFile(); diff --git a/src/main/java/org/apache/sling/feature/scanner/Scanner.java b/src/main/java/org/apache/sling/feature/scanner/Scanner.java index 81d5350..877ce92 100644 --- a/src/main/java/org/apache/sling/feature/scanner/Scanner.java +++ b/src/main/java/org/apache/sling/feature/scanner/Scanner.java @@ -29,15 +29,13 @@ import org.apache.sling.feature.ArtifactId; import org.apache.sling.feature.Bundles; import org.apache.sling.feature.Extension; import org.apache.sling.feature.Feature; +import org.apache.sling.feature.analyser.extensions.AnalyserMetaDataExtension; import org.apache.sling.feature.builder.ArtifactProvider; import org.apache.sling.feature.scanner.impl.BundleDescriptorImpl; import org.apache.sling.feature.scanner.impl.FeatureDescriptorImpl; import org.apache.sling.feature.scanner.spi.ExtensionScanner; import org.apache.sling.feature.scanner.spi.FrameworkScanner; -import javax.json.JsonObject; -import javax.json.JsonValue; - /** * The scanner is a service that scans items and provides descriptions for * these. The following items can be scanned individually @@ -176,7 +174,7 @@ public class Scanner { private void scanExtensions(final Feature f, final ContainerDescriptor desc) throws IOException { for (final Extension ext : f.getExtensions()) { - if (ext.getName().equals("analyser-metadata")) { + if (AnalyserMetaDataExtension.isAnalyserMetaDataExtension(ext)) { continue; } ContainerDescriptor extDesc = null; @@ -240,34 +238,21 @@ public class Scanner { private void populateCache(Feature feature) throws IOException { - Extension extension = feature.getExtensions().getByName("analyser-metadata"); + AnalyserMetaDataExtension extension = AnalyserMetaDataExtension.getAnalyserMetaDataExtension(feature); + if (extension != null) { - JsonObject json = extension.getJSONStructure().asJsonObject(); - for (Map.Entry<String, JsonValue> entry : json.entrySet()) { - ArtifactId id = ArtifactId.fromMvnId(entry.getKey()); - if (feature.getBundles().containsExact(id)) { - Artifact bundle = feature.getBundles().getExact(id); - final String key = id.toMvnId().concat(":") - .concat(String.valueOf(bundle.getStartOrder())).concat(":") - .concat(Stream.of(bundle.getFeatureOrigins()).map(ArtifactId::toMvnId).collect(Collectors.joining(","))); - if (this.cache.get(key) == null) { - JsonObject headers = entry.getValue().asJsonObject(); - if (headers.containsKey("manifest")) { - URL file; - try { - file = artifactProvider.provide(id); - } catch (Exception ex) { - // Ignore, as we have the metadata cached we assume getting the file is a best effort. - file = null; - } - Manifest manifest = new Manifest(); - JsonObject manifestHeaders = headers.getJsonObject("manifest"); - for (String name : manifestHeaders.keySet()) { - manifest.getMainAttributes().putValue(name, manifestHeaders.getString(name)); - } - BundleDescriptor desc = new BundleDescriptorImpl(bundle, file, manifest, bundle.getStartOrder()); - this.cache.put(key, desc); - } + for (Artifact bundle : feature.getBundles()) { + ArtifactId id = bundle.getId(); + final String key = id.toMvnId().concat(":") + .concat(String.valueOf(bundle.getStartOrder())).concat(":") + .concat(Stream.of(bundle.getFeatureOrigins()).map(ArtifactId::toMvnId).collect(Collectors.joining(","))); + if (this.cache.get(key) == null) { + Map<String, String> headers = extension.getManifest(id); + if (headers != null) { + Manifest manifest = new Manifest(); + headers.forEach(manifest.getMainAttributes()::putValue); + BundleDescriptor desc = new BundleDescriptorImpl(bundle, artifactProvider, manifest, bundle.getStartOrder()); + this.cache.put(key, desc); } } } diff --git a/src/main/java/org/apache/sling/feature/scanner/impl/BundleDescriptorImpl.java b/src/main/java/org/apache/sling/feature/scanner/impl/BundleDescriptorImpl.java index 641d269..7620946 100644 --- a/src/main/java/org/apache/sling/feature/scanner/impl/BundleDescriptorImpl.java +++ b/src/main/java/org/apache/sling/feature/scanner/impl/BundleDescriptorImpl.java @@ -21,10 +21,13 @@ import org.apache.felix.utils.manifest.Parser; import org.apache.felix.utils.resource.ResourceBuilder; import org.apache.felix.utils.resource.ResourceImpl; import org.apache.sling.feature.Artifact; +import org.apache.sling.feature.builder.ArtifactProvider; import org.apache.sling.feature.io.IOUtils; import org.apache.sling.feature.scanner.BundleDescriptor; import org.apache.sling.feature.scanner.PackageInfo; import org.osgi.framework.Constants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.URL; @@ -44,6 +47,11 @@ import java.util.stream.Collectors; public class BundleDescriptorImpl extends BundleDescriptor { + private static final Logger logger = LoggerFactory.getLogger(BundleDescriptorImpl.class); + + /** The provider to use if now file is given up-front **/ + private final ArtifactProvider artifactProvider; + /** The bundle symbolic name. */ private String symbolicName; @@ -59,6 +67,7 @@ public class BundleDescriptorImpl /** The physical file for analyzing. */ private final URL artifactFile; + /** The corresponding artifact from the feature. */ private final Artifact artifact; @@ -71,17 +80,26 @@ public class BundleDescriptorImpl public BundleDescriptorImpl(final Artifact a, final URL file, final int startLevel) throws IOException { - this(a, file, getManifest(file), startLevel); + this(a, file, null, getManifest(file), startLevel); + } + + public BundleDescriptorImpl(final Artifact a, + final ArtifactProvider provider, + final Manifest manifest, + final int startLevel) throws IOException { + this(a, null, provider, manifest, startLevel); } public BundleDescriptorImpl(final Artifact a, final URL file, + final ArtifactProvider provider, final Manifest manifest, final int startLevel) throws IOException { super(a.getId().toMvnId()); this.artifact = a; this.startLevel = startLevel; this.artifactFile = file; + this.artifactProvider = provider; if ( manifest == null ) { throw new IOException("File has no manifest"); } @@ -120,7 +138,16 @@ public class BundleDescriptorImpl @Override public URL getArtifactFile() { - return artifactFile; + URL result = null; + if (artifactFile == null && artifactProvider != null) { + try { + result = artifactProvider.provide(artifact.getId()); + } catch (Exception ex) { + // Ignore, we assume this is a best effort and callers can handle a null. + logger.debug("Unable to get artifact file for: " + artifact.getId(), ex); + } + } + return result; } @Override diff --git a/src/main/java/org/apache/sling/feature/scanner/impl/ContentPackageScanner.java b/src/main/java/org/apache/sling/feature/scanner/impl/ContentPackageScanner.java index bffd929..417f7a1 100644 --- a/src/main/java/org/apache/sling/feature/scanner/impl/ContentPackageScanner.java +++ b/src/main/java/org/apache/sling/feature/scanner/impl/ContentPackageScanner.java @@ -43,7 +43,7 @@ import org.slf4j.LoggerFactory; public class ContentPackageScanner { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private static final Logger logger = LoggerFactory.getLogger(ContentPackageScanner.class); private final byte[] buffer = new byte[65536]; @@ -54,18 +54,19 @@ public class ContentPackageScanner { } public Set<ContentPackageDescriptor> scan(final Artifact desc, final URL file) throws IOException { - final Set<ContentPackageDescriptor> contentPackages = new HashSet<>(); - final ContentPackageDescriptor cp = new ContentPackageDescriptor(file.getPath()); - final int lastDot = file.getPath().lastIndexOf("."); - cp.setName(file.getPath().substring(file.getPath().lastIndexOf("/") + 1, lastDot)); - cp.setArtifact(desc); - cp.setArtifactFile(file); + if (file != null) { + final ContentPackageDescriptor cp = new ContentPackageDescriptor(file.getPath()); + final int lastDot = file.getPath().lastIndexOf("."); + cp.setName(file.getPath().substring(file.getPath().lastIndexOf("/") + 1, lastDot)); + cp.setArtifact(desc); + cp.setArtifactFile(file); - extractContentPackage(cp, contentPackages, file); + extractContentPackage(cp, contentPackages, file); - contentPackages.add(cp); - cp.lock(); + contentPackages.add(cp); + cp.lock(); + } return contentPackages; } diff --git a/src/main/java/org/apache/sling/feature/scanner/impl/ContentPackagesExtensionScanner.java b/src/main/java/org/apache/sling/feature/scanner/impl/ContentPackagesExtensionScanner.java index 22d0971..ccf48b6 100644 --- a/src/main/java/org/apache/sling/feature/scanner/impl/ContentPackagesExtensionScanner.java +++ b/src/main/java/org/apache/sling/feature/scanner/impl/ContentPackagesExtensionScanner.java @@ -27,9 +27,11 @@ import org.apache.sling.feature.Feature; import org.apache.sling.feature.builder.ArtifactProvider; import org.apache.sling.feature.scanner.ContainerDescriptor; import org.apache.sling.feature.scanner.spi.ExtensionScanner; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class ContentPackagesExtensionScanner implements ExtensionScanner { - + private static final Logger logger = LoggerFactory.getLogger(ContentPackageScanner.class); @Override public String getId() { return Extension.EXTENSION_NAME_CONTENT_PACKAGES; @@ -56,15 +58,27 @@ public class ContentPackagesExtensionScanner implements ExtensionScanner { final ContainerDescriptor cd = new ContainerDescriptor(feature.getId().toMvnId() + "(" + getId() + ")") {}; for(final Artifact a : extension.getArtifacts()) { - final URL file = provider.provide(a.getId()); - if ( file == null ) { - throw new IOException("Unable to find file for " + a.getId()); + URL file = null; + try { + file = provider.provide(a.getId()); + } catch (Exception ex) { + logger.debug("Unable to get artifact file for: " + a.getId(), ex); } - final Set<ContentPackageDescriptor> pcks = scanner.scan(a, file); - for(final ContentPackageDescriptor desc : pcks) { + if (file != null) { + final Set<ContentPackageDescriptor> pcks = scanner.scan(a, file); + for (final ContentPackageDescriptor desc : pcks) { + cd.getArtifactDescriptors().add(desc); + cd.getBundleDescriptors().addAll(desc.bundles); + } + } + else { + ContentPackageDescriptor desc = new ContentPackageDescriptor(a.getId().toMvnUrl()); + final int lastDot = a.getId().toMvnPath().lastIndexOf("."); + desc.setName(a.getId().toMvnPath().substring(a.getId().toMvnPath().lastIndexOf("/") + 1, lastDot)); + desc.setArtifact(a); + desc.lock(); cd.getArtifactDescriptors().add(desc); - cd.getBundleDescriptors().addAll(desc.bundles); } } diff --git a/src/test/java/org/apache/sling/feature/analyser/extensions/AnalyserMetaDataExtensionTest.java b/src/test/java/org/apache/sling/feature/analyser/extensions/AnalyserMetaDataExtensionTest.java new file mode 100644 index 0000000..fbb388a --- /dev/null +++ b/src/test/java/org/apache/sling/feature/analyser/extensions/AnalyserMetaDataExtensionTest.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.feature.analyser.extensions; + +import org.apache.sling.feature.*; +import org.apache.sling.feature.scanner.BundleDescriptor; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.jar.Manifest; + +public class AnalyserMetaDataExtensionTest { + @Test + public void testAnalyserMetaDataExtension() throws Exception { + Extension extension = new Extension(ExtensionType.JSON, AnalyserMetaDataExtension.EXTENSION_NAME, ExtensionState.REQUIRED); + extension.setJSON("{}"); + AnalyserMetaDataExtension analyserMetaDataExtension = AnalyserMetaDataExtension.getAnalyserMetaDataExtension(extension); + + Assert.assertNotNull(analyserMetaDataExtension); + Manifest manifest = new Manifest(); + manifest.getMainAttributes().putValue("foo", "bar"); + BundleDescriptor descriptor = Mockito.mock(BundleDescriptor.class); + Artifact artifact = new Artifact(ArtifactId.fromMvnId("org:foo:0.1")); + Mockito.when(descriptor.getManifest()).thenReturn(manifest); + Mockito.when(descriptor.getArtifact()).thenReturn(artifact); + analyserMetaDataExtension.add(descriptor); + analyserMetaDataExtension.setReportErrors(artifact.getId(), false); + + analyserMetaDataExtension.toExtension(extension); + + Extension testExtension = new Extension(ExtensionType.JSON, AnalyserMetaDataExtension.EXTENSION_NAME, ExtensionState.REQUIRED); + testExtension.setJSON(extension.getJSON()); + + Assert.assertTrue(AnalyserMetaDataExtension.isAnalyserMetaDataExtension(testExtension)); + + AnalyserMetaDataExtension testAnalyserMetaDataExtension = AnalyserMetaDataExtension.getAnalyserMetaDataExtension(testExtension); + + Assert.assertNotNull(testAnalyserMetaDataExtension.getManifest(artifact.getId())); + Assert.assertEquals("bar", testAnalyserMetaDataExtension.getManifest(artifact.getId()).get("foo")); + + Assert.assertFalse(testAnalyserMetaDataExtension.reportError(artifact.getId())); + + } +} diff --git a/src/test/java/org/apache/sling/feature/analyser/task/impl/AnalyzerTaskProviderTest.java b/src/test/java/org/apache/sling/feature/analyser/task/impl/AnalyserTaskProviderTest.java similarity index 98% rename from src/test/java/org/apache/sling/feature/analyser/task/impl/AnalyzerTaskProviderTest.java rename to src/test/java/org/apache/sling/feature/analyser/task/impl/AnalyserTaskProviderTest.java index cec3f0a..ded11e6 100644 --- a/src/test/java/org/apache/sling/feature/analyser/task/impl/AnalyzerTaskProviderTest.java +++ b/src/test/java/org/apache/sling/feature/analyser/task/impl/AnalyserTaskProviderTest.java @@ -31,7 +31,7 @@ import java.util.ServiceLoader; import org.apache.sling.feature.analyser.task.AnalyserTask; import org.junit.Test; -public final class AnalyzerTaskProviderTest { +public final class AnalyserTaskProviderTest { private static int allTasks() { int size = 0; diff --git a/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckApisJarsPropertiesTest.java b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckApisJarsPropertiesTest.java index 983b43f..e4c527b 100644 --- a/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckApisJarsPropertiesTest.java +++ b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckApisJarsPropertiesTest.java @@ -53,6 +53,30 @@ public class CheckApisJarsPropertiesTest { } @Override + public void reportArtifactWarning(ArtifactId artifactId, String message) { + System.out.println("[WARN] " + message); + warnings.add(message); + } + + @Override + public void reportArtifactError(ArtifactId artifactId, String message) { + System.out.println("[ERROR] " + message); + errors.add(message); + } + + @Override + public void reportExtensionWarning(String extension, String message) { + System.out.println("[WARN] " + message); + warnings.add(message); + } + + @Override + public void reportExtensionError(String extension, String message) { + System.out.println("[ERROR] " + message); + errors.add(message); + } + + @Override public void reportError(String message) { System.out.println("[ERROR] " + message); errors.add(message); diff --git a/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckBundleExportsImportsTest.java b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckBundleExportsImportsTest.java index 5ebae03..ad2e4a5 100644 --- a/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckBundleExportsImportsTest.java +++ b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckBundleExportsImportsTest.java @@ -75,8 +75,8 @@ public class CheckBundleExportsImportsTest { Mockito.when(ctx.getFeatureDescriptor()).thenReturn(fd); t.execute(ctx); - Mockito.verify(ctx, Mockito.times(2)).reportError(Mockito.anyString()); - Mockito.verify(ctx).reportError(Mockito.contains("org.foo.e")); + Mockito.verify(ctx, Mockito.times(1)).reportArtifactError(Mockito.any(), Mockito.anyString()); + Mockito.verify(ctx).reportArtifactError(Mockito.any(), Mockito.contains("org.foo.e")); Mockito.verify(ctx).reportError(Mockito.contains("marked as 'complete'")); Mockito.verify(ctx, Mockito.never()).reportWarning(Mockito.anyString()); } @@ -118,8 +118,8 @@ public class CheckBundleExportsImportsTest { Mockito.when(ctx.getFeatureDescriptor()).thenReturn(fd); t.execute(ctx); - Mockito.verify(ctx).reportError(Mockito.contains("org.foo.e")); - Mockito.verify(ctx, Mockito.times(1)).reportError(Mockito.anyString()); + Mockito.verify(ctx).reportArtifactError(Mockito.any(), Mockito.contains("org.foo.e")); + Mockito.verify(ctx, Mockito.never()).reportError(Mockito.anyString()); Mockito.verify(ctx, Mockito.never()).reportWarning(Mockito.anyString()); } diff --git a/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckBundleNativeCodeTest.java b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckBundleNativeCodeTest.java index cffc839..d8a48d4 100644 --- a/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckBundleNativeCodeTest.java +++ b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckBundleNativeCodeTest.java @@ -68,7 +68,7 @@ public class CheckBundleNativeCodeTest { fdAddBundle(fd, "g:b1:1", "something"); task.execute(ctx); - Mockito.verify(ctx, Mockito.times(1)).reportError(Mockito.anyString()); + Mockito.verify(ctx, Mockito.times(1)).reportArtifactError(Mockito.any(), Mockito.anyString()); Mockito.verify(ctx, Mockito.never()).reportWarning(Mockito.anyString()); } diff --git a/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckRepoinitTest.java b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckRepoinitTest.java index 1355e52..0cf89bc 100644 --- a/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckRepoinitTest.java +++ b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckRepoinitTest.java @@ -141,6 +141,26 @@ public class CheckRepoinitTest { } @Override + public void reportArtifactWarning(ArtifactId artifactId, String message) { + + } + + @Override + public void reportArtifactError(ArtifactId artifactId, String message) { + errors.add(message); + } + + @Override + public void reportExtensionWarning(String extension, String message) { + + } + + @Override + public void reportExtensionError(String extension, String message) { + errors.add(message); + } + + @Override public void reportError(String message) { errors.add(message); } diff --git a/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckRequirementsCapabilitiesTest.java b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckRequirementsCapabilitiesTest.java index ea693b9..b08e095 100644 --- a/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckRequirementsCapabilitiesTest.java +++ b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckRequirementsCapabilitiesTest.java @@ -93,7 +93,7 @@ public class CheckRequirementsCapabilitiesTest { CheckRequirementsCapabilities crc = new CheckRequirementsCapabilities(); crc.execute(ctx); - Mockito.verify(ctx).reportError(Mockito.contains("org.foo.bar")); + Mockito.verify(ctx).reportArtifactError(Mockito.any(), Mockito.contains("org.foo.bar")); } @Test
