org.metaeffekt.notice.engine.utils.NoticeUtils 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.engine.utils;
import com.metaeffekt.artifact.terms.model.NormalizationMetaData;
import com.metaeffekt.artifact.terms.model.TermsMetaData;
import org.apache.commons.lang.StringUtils;
import org.metaeffekt.common.notice.model.ComponentDefinition;
import org.metaeffekt.common.notice.model.NoticeParameters;
import org.metaeffekt.core.inventory.processor.report.PreFormattedEscapeUtils;
import org.metaeffekt.notice.engine.NoticeEngine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.stream.Collectors;
public class NoticeUtils {
private static final Logger LOG = LoggerFactory.getLogger(NoticeUtils.class);
public static final String SEPARATOR_PLUS = " + ";
public static final String SEPARATOR_COMMA = ", ";
public final static PreFormattedEscapeUtils ESCAPE_UTILS = new PreFormattedEscapeUtils();
public final NormalizationMetaData normalizationMetaData;
public NoticeUtils(NormalizationMetaData normalizationMetaData) {
this.normalizationMetaData = normalizationMetaData;
}
private TermsMetaData getTermsMetaDataNullable(String license) {
return normalizationMetaData.resolveTermsMetaData(license);
}
private TermsMetaData getTermsMetaDataNonNull(String license) {
final TermsMetaData termsMetaData = normalizationMetaData.resolveTermsMetaData(license);
if (termsMetaData == null) {
return createDefaultTermsMetaData(license);
} else {
return termsMetaData;
}
}
public static TermsMetaData createDefaultTermsMetaData(String name){
TermsMetaData tmd = new TermsMetaData();
tmd.setCanonicalName(name);
tmd.setRequiresNote(true);
tmd.setRequiresCopyright(false);
tmd.setTemporaryLMD(true);
return tmd;
}
public String enumerate(List originalLicenseList, String conjunction, String article, String language) {
if (originalLicenseList == null || originalLicenseList.isEmpty()) return "";
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < originalLicenseList.size(); i++) {
String license = originalLicenseList.get(i);
if (license.contains(SEPARATOR_PLUS)) {
license = enrichLicenseOption(license, article, language);
} else {
license = prependArticle(license, article, language);
}
if (i > 0) sb.append(SEPARATOR_COMMA);
if (i == originalLicenseList.size() - 1 && originalLicenseList.size() > 1) {
sb.append(conjunction).append(" ");
}
sb.append(license);
}
return sb.toString();
}
private String enrichLicenseOption(String licenseOption, String article, String language) {
final String[] licenses = licenseOption.split(" \\+ ");
final StringBuilder internalSb = new StringBuilder();
for (String license : licenses) {
if (internalSb.length() > 0) {
internalSb.append(" ").append(getTranslatedTerm("OR_" + language)).append(" ");
}
internalSb.append(prependArticle(license, article, language));
}
return getTranslatedTerm("EITHER_" + language) + " " + internalSb;
}
private String prependArticle(String license, String article, String language) {
final TermsMetaData termsMetaData = getTermsMetaDataNonNull(license);
if (!termsMetaData.isArticleRequired() && language.equals("en_US")) {
return license;
}
if (license.startsWith("Permission Terms") && language.equals("de_DE")) {
return "von " + license;
}
return article + " " + license;
}
//TODO: Put this in a resource file
private String getTranslatedTerm(String term) {
if (term.equals("OR_en_US")) return "or";
if (term.equals("OR_de_DE")) return "oder";
if (term.equals("EITHER_en_US")) return "either";
if (term.equals("EITHER_de_DE")) return "entweder";
return null;
}
public String enumerateX(List list, String conjunction, String article, String language) {
String s = enumerate(list, conjunction, article, language);
s = StringUtils.capitalize(s);
return s;
}
public List getAssociatedLicenses(NoticeParameters noticeParameters) {
final Set aggregated = new HashSet<>(getAssociatedLicenses(noticeParameters.getComponent()));
for (ComponentDefinition componentDefinition : noticeParameters.getSubcomponents()) {
aggregated.addAll(getAssociatedLicenses(componentDefinition));
}
return aggregated.stream().sorted(String::compareToIgnoreCase).collect(Collectors.toList());
}
public List getEffectiveLicenses(NoticeParameters noticeParameters) {
final Set aggregated = new HashSet<>(getEffectiveLicenses(noticeParameters.getComponent()));
for (ComponentDefinition componentDefinition : noticeParameters.getSubcomponents()) {
aggregated.addAll(getEffectiveLicenses(componentDefinition));
}
return aggregated.stream().sorted(String::compareToIgnoreCase).collect(Collectors.toList());
}
public boolean hasLicensingOption(NoticeParameters noticeParameters) {
return !getAssociatedLicenses(noticeParameters).equals(getEffectiveLicenses(noticeParameters));
}
public List getComponentsWithLicenseOption(NoticeParameters noticeParameters) {
List componentDefinitionList = new ArrayList();
if (getOptionalLicenses(noticeParameters.getComponent()) == true) {
componentDefinitionList.add((noticeParameters.getComponent()));
}
for (ComponentDefinition componentDefinition : noticeParameters.getSubcomponents()) {
if (getOptionalLicenses(componentDefinition) == true) {
componentDefinitionList.add((componentDefinition));
}
}
return componentDefinitionList;
}
private boolean getOptionalLicenses(ComponentDefinition component) {
return !(component.getEffectiveLicenses() == null);
}
private Collection getAssociatedLicenses(ComponentDefinition component) {
return component.getAssociatedLicenses();
}
public Collection getEffectiveLicenses(ComponentDefinition component) {
if (component.getEffectiveLicenses() == null || component.getEffectiveLicenses().isEmpty()) {
return component.getAssociatedLicenses();
} else {
return component.getEffectiveLicenses();
}
}
public static class NoticeSummary {
boolean requiresSourceCodeProvision = false;
boolean requiresLicenseAndNoticeProvision = false;
List licensesRequiringSourceCodeProvisioning = new ArrayList<>();
List licensesRequiringLicenseAndNoticeProvisioning = new ArrayList<>();
public List getLicensesRequiringLicenseAndNoticeProvisioning() {
return licensesRequiringLicenseAndNoticeProvisioning;
}
public List getLicensesRequiringSourceCodeProvisioning() {
return licensesRequiringSourceCodeProvisioning;
}
public boolean isRequiresLicenseAndNoticeProvision() {
return requiresLicenseAndNoticeProvision;
}
public boolean isRequiresSourceCodeProvision() {
return requiresSourceCodeProvision;
}
@Override
public String toString() {
return "NoticeSummary{" +
"requiresSourceCodeProvision=" + requiresSourceCodeProvision +
", requiresLicenseAndNoticeProvision=" + requiresLicenseAndNoticeProvision +
", licensesRequiringSourceCodeProvisioning=" + licensesRequiringSourceCodeProvisioning +
", licensesRequiringLicenseAndNoticeProvisioning=" + licensesRequiringLicenseAndNoticeProvisioning +
'}';
}
}
public NoticeSummary evaluateMeta(NoticeParameters noticeParameters) throws Exception {
List effectiveLicense = getEffectiveLicenses(noticeParameters);
NoticeSummary noticeSummary = new NoticeSummary();
for (String license : effectiveLicense) {
TermsMetaData termsMetaData = getTermsMetaDataNonNull(license);
if (termsMetaData.isRequiresSourceCodeProvision()) {
noticeSummary.requiresSourceCodeProvision = true;
noticeSummary.licensesRequiringSourceCodeProvisioning.add(license);
}
}
return noticeSummary;
}
public String getLicenseTemplateName(String license, NoticeEngine noticeEngine) {
try {
/*
* 1. If templateId is specified in TMD: return template ID
* 2. If license exists in noticeTemplate: return license
* 3. If representedAs of license exists in noticeTemplate: return representedAs
* 4. noticeID of representedLicense
* 5. Repeat 2 and 3 with updatedCanonicalName (canonicalNameHistory)
* 6. return Generate Template if generation possible
* 7. return Default Template
*/
final String language = noticeEngine.getProjectContext().getLanguageMode().toString();
String template;
TermsMetaData tmd = normalizationMetaData.resolveTermsMetaData(license);
// resolve using dedicated template id; the tmd links to the template
if (tmd != null) {
// continue with updated license name
license = tmd.getCanonicalName();
if (tmd.getNoticeTemplateId() != null) {
template = "notice-template/" + language + "/template-id/" + tmd.getNoticeTemplateId() + ".vm";
if (noticeEngine.resourceExists(template)) return template;
}
}
template = "notice-template/" + language + "/license-templates/" + license + ".vm";
// the license may have been renamed, without updating the template name
if (tmd != null && tmd.getCanonicalNameHistory() != null) {
for (String historicalCanonicalName : tmd.getCanonicalNameHistory()) {
template = "notice-template/" + language + "/license-templates/" + historicalCanonicalName + ".vm";
if (noticeEngine.resourceExists(template)) break;
}
}
// return in case the specific template exists
if (noticeEngine.resourceExists(template)) return template;
// continue via representedLicenseName
String representedLicenseName = representedLicenseName(license);
template = "notice-template/" + language + "/license-templates/" + representedLicenseName + ".vm";
if (noticeEngine.resourceExists(template)) return template;
tmd = getTermsMetaDataNullable(representedLicenseName);
if (tmd != null) {
if (tmd.getNoticeTemplateId() != null) {
template = "notice-template/" + language + "/template-id/" + tmd.getNoticeTemplateId() + ".vm";
if (noticeEngine.resourceExists(template)) return template;
}
}
// history fallback; should not be required anymore; since covered above
final Map historicalCanonicalNameMap = normalizationMetaData.getHistoricalCanonicalNameMap();
if (historicalCanonicalNameMap.containsValue(license)) {
for (String key : historicalCanonicalNameMap.keySet()) {
String value = historicalCanonicalNameMap.get(key);
if (value.equals(license)) {
String noticeTemplateID = getTermsMetaDataNonNull(key).getNoticeTemplateId();
if (noticeTemplateID != null) {
template = "notice-template/" + language + "/template-id/" + noticeTemplateID + ".vm";
if (noticeEngine.resourceExists(template)) return template;
}
template = "notice-template/" + language + "/license-templates/" + key + ".vm";
if (noticeEngine.resourceExists(template)) return template;
}
if (value.equals(representedLicenseName)) {
String noticeTemplateID = getTermsMetaDataNonNull(key).getNoticeTemplateId();
if (noticeTemplateID != null) {
template = "notice-template/" + language + "/template-id/" + noticeTemplateID + ".vm";
if (noticeEngine.resourceExists(template)) return template;
}
template = "notice-template/" + language + "/license-templates/" + key + ".vm";
if (noticeEngine.resourceExists(template)) return template;
}
}
}
if (generateTemplatePossible(license)) {
return "notice-template/" + language + "/license-templates/Generate Template.vm";
} else {
return "notice-template/" + language + "/license-templates/Default Template.vm";
}
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
private boolean generateTemplatePossible(String license) {
final TermsMetaData tmd = getTermsMetaDataNullable(license);
if (tmd == null) return false;
if (tmd.getType() != null && (tmd.isException() || tmd.isExpression() || tmd.isMarker())) return false;
if (license.contains("(or any later version)")) return false;
if (tmd.isUnspecific()) return false;
return tmd.getRequiresCopyright() != null && tmd.getRequiresLicenseText() != null;
}
public List processingCopyrights(List inputCopyrights) {
List copyrights = new ArrayList<>();
HashSet hashSet = new HashSet<>(inputCopyrights);
copyrights.addAll(hashSet);
copyrights.sort(Comparator.naturalOrder());
return copyrights;
}
public String getDisplayName(String license) {
TermsMetaData termsMetaData = getTermsMetaDataNonNull(license);
if (termsMetaData.getDisplayName() != null) {
return termsMetaData.getDisplayName();
}
return license;
}
public List getDisplayNames(List licenses) {
List displayNames = new ArrayList<>();
for (String license : licenses) {
displayNames.add(getDisplayName(license));
}
return displayNames;
}
public String representedLicenseName(String license) {
String representedLicenseName;
TermsMetaData termsMetaData = getTermsMetaDataNonNull(license);
if (termsMetaData.getRepresentedAs() != null) {
TermsMetaData representedTMD = getTermsMetaDataNonNull(termsMetaData.getRepresentedAs());
if (representedTMD.getBaseTerms() != null) {
representedLicenseName = representedTMD.getBaseTerms();
}
else {
representedLicenseName = termsMetaData.getRepresentedAs();
}
}
else if (termsMetaData.getBaseTerms() != null){
representedLicenseName = termsMetaData.getBaseTerms();
}
else {
representedLicenseName = license;
}
return representedLicenseName;
}
public String getLicenseTemplate(String effectiveLicense, ComponentDefinition componentDefinition) throws Exception {
TermsMetaData termsMetaData = getTermsMetaDataNonNull(effectiveLicense);
String licenseTemplate = termsMetaData.getLicenseTemplate();
if (licenseTemplate == null && termsMetaData.getRepresentedAs() != null) {
// in case no template was found use the represented license as fallback
termsMetaData = getTermsMetaDataNonNull(termsMetaData.getRepresentedAs());
licenseTemplate = termsMetaData.getLicenseTemplate();
}
if (licenseTemplate == null) {
return "";
}
// in case a template is available the variable replacement is performed
return replacePlaceHolders(licenseTemplate, componentDefinition);
}
private String replacePlaceHolders(String licenseTemplate, ComponentDefinition componentDefinition) throws Exception {
// Every key should only be used once per license and there should not be multiple Licenses containing
// placeholders within one component.
if (!licenseTemplate.contains("{{")) return licenseTemplate;
if (componentDefinition.getVariables() != null) {
for (Map.Entry entry : componentDefinition.getVariables().entrySet()) {
String key = "{{" + entry.getKey() + "}}";
if (licenseTemplate.contains(key)) {
licenseTemplate = licenseTemplate.replace(key, ESCAPE_UTILS.xml(entry.getValue()));
} else {
LOG.warn("The variable {} can't be found in the license template.", entry.getKey());
}
}
}
// FIXME: No validation whether the input is set at the right placeHolder
if (licenseTemplate.matches(".*\\{\\{([^\\}]+)}}.*")) {
throwException("There are still un-replaced variables in the notice Parameter:\n" +
"======\n" +
"identified license: " + componentDefinition.getAssociatedLicenses() + "\n" +
"license template:\n" +
">>>>>>\n" +
licenseTemplate.replace("{{", "{*******{").replace("}}", "}******}") + "\n" +
"<<<<<<\n");
}
return licenseTemplate;
}
public boolean nameExisting(ComponentDefinition componentDefinition){
if (componentDefinition.getName() != null){
return true;
}
return false;
}
public boolean componentSeparationRequired(NoticeParameters noticeParameters){
boolean componentSeparationRequired = false;
List effectiveLicenses = new ArrayList<>();
for (ComponentDefinition subcomponent : noticeParameters.getSubcomponents()){
if (nameExisting(subcomponent)) componentSeparationRequired = true;
effectiveLicenses.addAll(subcomponent.getAssociatedLicenses());
}
for (String license : getEffectiveLicenses(noticeParameters.getComponent())){
if (effectiveLicenses.contains(license)) componentSeparationRequired = true;
}
if (componentSeparationRequired) return true;
return false;
}
public List getSelectedComponents(List subcomponents, boolean namedComponents){
List selectedComponents = new ArrayList<>();
for (ComponentDefinition subcomponent : subcomponents){
if (nameExisting(subcomponent) && namedComponents){
selectedComponents.add(subcomponent);
}
else if (!nameExisting(subcomponent) && !namedComponents){
selectedComponents.add(subcomponent);
}
}
return selectedComponents;
}
public List getEffectiveLicensesUnnamedComponents(List subcomponents){
List unnamedComponents = getSelectedComponents(subcomponents, false);
List effectiveLicenses = new ArrayList<>();
for (ComponentDefinition unnamedComponent : unnamedComponents){
effectiveLicenses.addAll(getEffectiveLicenses(unnamedComponent));
}
Set set = new HashSet<>(effectiveLicenses);
effectiveLicenses.clear();
effectiveLicenses.addAll(set);
return effectiveLicenses;
}
private void throwException(String exception){
throw new IllegalStateException(exception);
}
public boolean requiresCopyright(String license) {
// only call if getRequiresCopyright was checked on null
final TermsMetaData termsMetaData = getTermsMetaDataNullable(license);
if (termsMetaData != null) {
return termsMetaData.getRequiresCopyright();
}
return false;
}
public boolean requiresLicenseText(String license) {
// only call if getRequiresLicenseText was checked on null
return getTermsMetaDataNonNull(license).getRequiresLicenseText();
}
public String getRightLicenseTemplate(String license) {
TermsMetaData tmd = getTermsMetaDataNullable(license);
if (tmd.getLicenseTemplate() != null) return license;
return representedLicenseName(license);
}
public NormalizationMetaData getNormalizationMetaData() {
return normalizationMetaData;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy