org.metaeffekt.notice.NoticeParameterProcessor Maven / Gradle / Ivy
/*
* Copyright 2021-2024 the original author or authors.
*
* Licensed 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.metaeffekt.notice;
import com.metaeffekt.artifact.analysis.utils.InventoryUtils;
import com.metaeffekt.artifact.analysis.utils.StringUtils;
import com.metaeffekt.artifact.terms.model.NormalizationMetaData;
import org.metaeffekt.common.notice.model.ComponentDefinition;
import org.metaeffekt.common.notice.model.NoticeParameters;
import org.metaeffekt.common.notice.model.ProjectContext;
import org.metaeffekt.core.inventory.processor.model.Artifact;
import org.metaeffekt.core.inventory.processor.model.Inventory;
import org.metaeffekt.core.inventory.processor.model.LicenseMetaData;
import org.metaeffekt.core.inventory.processor.reader.InventoryReader;
import org.metaeffekt.notice.engine.NoticeEngine;
import org.metaeffekt.notice.engine.utils.NoticeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.metaeffekt.artifact.analysis.metascan.Constants.KEY_NOTICE_PARAMETER;
import static org.metaeffekt.core.inventory.InventoryUtils.joinEffectiveLicenses;
import static org.metaeffekt.core.inventory.processor.model.Constants.ASTERISK;
import static org.metaeffekt.core.inventory.processor.model.Constants.VERSION_PLACHOLDER_PREFIX;
/**
* Utility primary used by the metaeffekt workbench using the {@link NoticeEngine} to process inventory content.
*/
public class NoticeParameterProcessor {
private static final Logger LOG = LoggerFactory.getLogger(NoticeParameterProcessor.class);
private final NoticeUtils noticeUtils;
public NoticeParameterProcessor(NormalizationMetaData normalizationMetaData) {
this.noticeUtils = new NoticeUtils(normalizationMetaData);
}
/**
* Iterates the artifacts in the inventory and processes the Notice Parameter column to produce
* {@link LicenseMetaData} including the resulting notice.
*
* @param inventory The inventory to process.
*/
public void updateNoticeFromNoticeParameter(Inventory inventory) {
updateNoticeFromNoticeParameter(inventory, null);
}
// FIXME: requires optimization; takes 1min (!!) on HD-AE
/**
* Iterates the artifacts in the inventory and processes the Notice Parameter column to produce
* {@link LicenseMetaData} including the resulting notice.
*
* @param inventory The inventory to process.
* @param projectContext The {@link ProjectContext} instance to be used.
*/
public void updateNoticeFromNoticeParameter(Inventory inventory, ProjectContext projectContext) {
final NoticeEngine noticeEngine = new NoticeEngine();
if (projectContext != null) {
noticeEngine.setProjectContext(projectContext);
}
if (inventory == null || inventory.getArtifacts() == null) return;
// Pass #1: asterisk and version placeholder
List secondPass = new ArrayList<>();
for (final Artifact artifact : inventory.getArtifacts()) {
if (!InventoryUtils.canCarryLicenseMetaData(artifact)) continue;
final String noticeParameterYaml = artifact.get(KEY_NOTICE_PARAMETER);
if (StringUtils.notEmpty(noticeParameterYaml)) {
if (artifact.getVersion().startsWith(VERSION_PLACHOLDER_PREFIX) ||
artifact.getVersion().equals(ASTERISK)) {
generateNoticeFromNoticeParameter(inventory, noticeEngine, artifact, noticeParameterYaml);
} else {
secondPass.add(artifact);
}
}
}
// Pass #2: all others (with version placeholder)
for (final Artifact artifact : secondPass) {
if (!InventoryUtils.canCarryLicenseMetaData(artifact)) continue;
final String noticeParameterYaml = artifact.get(KEY_NOTICE_PARAMETER);
if (StringUtils.notEmpty(noticeParameterYaml)) {
generateNoticeFromNoticeParameter(inventory, noticeEngine, artifact, noticeParameterYaml);
}
}
}
private void generateNoticeFromNoticeParameter(Inventory inventory, NoticeEngine noticeEngine, Artifact artifact, String noticeParameterYaml) {
try {
final NoticeParameters parameter = readNoticeParameter(noticeParameterYaml);
// artifact component name is the reference
if (StringUtils.notEmpty(artifact.getComponent())) {
ComponentDefinition component = parameter.getComponent();
if (component == null) {
component = new ComponentDefinition();
parameter.setComponent(component);
}
component.setName(artifact.getComponent());
}
// TODO: update effective license dependent on ProjectContext
final ComponentDefinition componentDefinition = parameter.getComponent();
updateEffectiveLicense(componentDefinition);
if (parameter.getSubcomponents() != null) {
for (ComponentDefinition subComponentDefinition : parameter.getSubcomponents()) {
updateEffectiveLicense(subComponentDefinition);
}
}
final String notice = noticeEngine.applyTemplate(parameter, noticeUtils.getNormalizationMetaData());
LicenseMetaData licenseMetaData = resolveOrCreateLicenseMetadata(inventory, artifact, parameter);
if (StringUtils.notEmpty(notice)) {
licenseMetaData.setNotice(notice);
addLicenseMetaData(inventory, artifact, licenseMetaData);
} else {
LOG.warn("No notice parameter for artifact [{}]. Cannot create notice.", artifact.deriveQualifier());
}
} catch (Exception e) {
LOG.error("Cannot process notice parameter for [{}]. Reason: [{}]", artifact.getId(), e.getMessage());
}
}
private void addLicenseMetaData(Inventory inventory, Artifact artifact, LicenseMetaData licenseMetaData) {
if (inventory.findMatchingLicenseMetaData(artifact) == null) {
if (licenseMetaData.getVersion() == null) throw new IllegalStateException("Version is null in " + artifact.getId() + ".");
if (licenseMetaData.getLicense() == null) throw new IllegalStateException("License is null in " + artifact.getId() + ".");
if (licenseMetaData.getComponent() == null) throw new IllegalStateException("Component is null in " + artifact.getId() + ".");
LOG.debug("Adding license metadata for {}/{}/{}.", artifact.getComponent(), artifact.getLicense(), artifact.getVersion());
inventory.getLicenseMetaData().add(licenseMetaData);
// check whether we generated an inconsistence
try {
inventory.findMatchingLicenseMetaData(artifact);
} catch (Exception e) {
// in case yes, we remove the just added license metadata
inventory.getLicenseMetaData().remove(licenseMetaData);
LOG.error("Inconsistency detected after creating license metadata for [{}].", artifact.deriveQualifier());
}
}
}
private void updateEffectiveLicense(ComponentDefinition componentDefinition) {
// FIXME: ProjectContext evaluation missing; currently using default in InventoryUtils
final List effectiveLicenses = componentDefinition.getEffectiveLicenses();
if (effectiveLicenses == null || effectiveLicenses.isEmpty()) {
final List associatedLicenses = componentDefinition.getAssociatedLicenses();
final String s = InventoryUtils.deriveEffectiveLicenses(associatedLicenses);
componentDefinition.setEffectiveLicenses(Arrays.asList(s.split("\\|")));
}
}
public LicenseMetaData resolveOrCreateLicenseMetadata(Inventory inventory, Artifact artifact, NoticeParameters noticeParameter) {
LicenseMetaData licenseMetaData = null;
// use existing
if (StringUtils.notEmpty(artifact.getComponent()) && StringUtils.hasText(artifact.getVersion()) && StringUtils.hasText(artifact.getLicense())) {
licenseMetaData = inventory.findMatchingLicenseMetaData(artifact);
}
// create new
if (licenseMetaData == null) {
licenseMetaData = new LicenseMetaData();
licenseMetaData.setComponent(artifact.getComponent());
licenseMetaData.setLicense(artifact.getLicense());
if (artifact.getVersion().startsWith(VERSION_PLACHOLDER_PREFIX)) {
licenseMetaData.setVersion(ASTERISK);
} else {
licenseMetaData.setVersion(artifact.getVersion());
}
licenseMetaData.set("Type", "automatic");
if (noticeParameter != null) {
licenseMetaData.setLicenseInEffect(joinEffectiveLicenses(noticeUtils.getEffectiveLicenses(noticeParameter)));
} else {
licenseMetaData.setLicenseInEffect(InventoryUtils.deriveEffectiveLicenses(artifact.getLicense()));
}
}
return licenseMetaData;
}
public void validateNoticeParameter(File inventoryFile) throws IOException {
final Inventory inventory = new InventoryReader().readInventory(inventoryFile);
validateNoticeParameter(inventory);
}
public void validateNoticeParameter(Inventory inventory) {
for (final Artifact artifact : inventory.getArtifacts()) {
final String noticeParameterYaml = artifact.get("Notice Parameter");
if (StringUtils.notEmpty(noticeParameterYaml)) {
try {
readNoticeParameter(noticeParameterYaml);
} catch (Exception e) {
LOG.error("Error parsing artifact {}.", artifact.getId());
LOG.error(e.getMessage(), e);
}
}
}
}
public NoticeParameters readNoticeParameter(String noticeParameterYaml) {
// preprocess (inventory conventions)
noticeParameterYaml = noticeParameterYaml.replaceAll("\n\\.\\.\\.\\.", "\n ");
noticeParameterYaml = noticeParameterYaml.replaceAll("\n\\.\\.", "\n ");
char nbsp = 160;
char sp = 10;
noticeParameterYaml = noticeParameterYaml.replace(nbsp, sp);
noticeParameterYaml = noticeParameterYaml.replaceAll("\\s\n", "\n");
// finally read the notice parameter
return NoticeParameters.readYaml(noticeParameterYaml);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy