All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.metaeffekt.artifact.analysis.metascan.MergedScanResult Maven / Gradle / Ivy

The newest version!
/*
 * 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 com.metaeffekt.artifact.analysis.metascan;

import com.metaeffekt.artifact.analysis.utils.FileUtils;
import com.metaeffekt.artifact.analysis.utils.StringUtils;
import com.metaeffekt.artifact.terms.model.MergedSegmentResult;
import com.metaeffekt.artifact.terms.model.Variables;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.metaeffekt.core.inventory.processor.model.Artifact;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;

public class MergedScanResult {

    private static final Logger LOG = LoggerFactory.getLogger(MergedScanResult.class);

    private List mergedScanResult = new ArrayList<>();

    public void setMergedScanResult(List mergedScanResult) {
        this.mergedScanResult = mergedScanResult;
    }

    public List getMergedScanResult() {
        return mergedScanResult;
    }


    public void mergeResults(Artifact artifact, File sourceDir) throws IOException {
        if (sourceDir == null) return;

        final File analysisDir = sourceDir.getParentFile();
        final String sourceFolderName = sourceDir.getName();

        // input
        final File targetFolder = new File(analysisDir, sourceFolderName + "-analysis");

        final File metaScanResultJson = FileUtils.findSingleFile(targetFolder, "*_metascan.json");
        final File scancodeResultJson = FileUtils.findSingleFile(targetFolder, "*_scancode.json");

        // validate all input folders available
        FileUtils.validateExists(analysisDir);

        if (metaScanResultJson == null || scancodeResultJson == null) {
            LOG.debug("No scan result found for artifact {}.", artifact.deriveQualifier());
            artifact.append("Errors", "Missing scan result", "|\n");
            return;
        }

        JSONArray segments;
        try {
            segments = new JSONObject(FileUtils.readFileToString(scancodeResultJson, StandardCharsets.UTF_8)).optJSONArray("files");
        } catch (JSONException e) {
            LOG.error("Cannot parse json file: " + scancodeResultJson.getAbsolutePath());
            throw new IllegalStateException(e.getMessage(), e);
        }

        // FIXME-KKL: when we have high-level artifacts, the number of segments may enormous. I expect that generating
        // a notice parameter for an asset with 1000 segments is not beneficial. For the moment we log the size
        LOG.debug("Number of segments used for deriving notice parameter: [{}]", segments.length());

        JSONArray result;
        try {
            result = new JSONArray(FileUtils.readFileToString(metaScanResultJson, StandardCharsets.UTF_8));
        } catch (JSONException e) {
            LOG.error("Cannot parse json file: " + metaScanResultJson.getAbsolutePath());
            throw new IllegalStateException(e.getMessage(), e);
        }

        for (int i = 0; i < result.length(); i++) {
            final JSONObject file = result.optJSONObject(i);
            JSONObject segmentsMetascan = file.optJSONObject("segments");
            final int segmentCount = file.optInt("segmentCount");
            for (int j = 0; j < segmentCount; j++) {
                final String segmentName = "segment-" + j;
                final JSONObject segmentMetascan = segmentsMetascan.optJSONObject(segmentName);
                final String filePath = file.optString("file");
                final String scancodePath = sourceFolderName + "-intermediate/" + filePath + "/" + segmentName + ".txt";
                final JSONObject segmentScancode = getSegmentFromScancode(segments, scancodePath);

                MergedSegmentResult mergedSegmentResult = new MergedSegmentResult();
                boolean add = false;
                if (segmentMetascan != null) {
                    mergedSegmentResult.setResolvedLicenses(extractFromMetascanResult(segmentMetascan.optJSONArray("resolvedLicenses")));
                    mergedSegmentResult.setNameMatches(extractFromMetascanResult(segmentMetascan.optJSONArray("nameMatches")));
                    mergedSegmentResult.setTextMatches(extractFromMetascanResult(segmentMetascan.optJSONArray("textMatches")));
                    mergedSegmentResult.setVariables(extractVariables(segmentMetascan.optJSONArray("variables")));
                    add = true;
                }
                if (segmentScancode != null) {
                    mergedSegmentResult.setCopyrights(extractCopyrights(segmentScancode));
                    mergedSegmentResult.setScancodeLicenses(extractScancodeLicenses(segmentScancode));
                    mergedSegmentResult.setScancodeLicenseKeys(extractScancodeLicenseKeys(segmentScancode));
                    mergedSegmentResult.setPath(scancodePath);
                    add = true;
                }
                if (add) {
                    mergedScanResult.add(mergedSegmentResult);
                }
            }
        }

    }

    private static JSONObject getSegmentFromScancode(JSONArray segments, String path) throws IOException {
        for (int i = 0; i < segments.length(); i++) {
            JSONObject segment = segments.optJSONObject(i);
            if (segment.optString("path").equals(path)) {
                return segment;
            }
        }
        return null;
    }

    private List extractCopyrights(JSONObject segment) throws IOException {
        final JSONArray copyrightsJson = segment.optJSONArray("copyrights");
        if (copyrightsJson != null) {
            final List copyrights = new ArrayList<>();
            for (int i = 0; i < copyrightsJson.length(); i++) {
                StringUtils.addNonEmptyString(copyrightsJson.getJSONObject(i).optString("copyright"), copyrights);
            }
            if (!copyrights.isEmpty()) {
                return copyrights;
            }
        }
        return Collections.emptyList();
    }

    private List extractScancodeLicenses(JSONObject segmentScancode) throws IOException {
        final List licenses = new ArrayList<>();
        final JSONArray licenseJson = segmentScancode.optJSONArray("licenses");
        if (licenseJson != null) {
            for (int k = 0; k < licenseJson.length(); k++) {
                StringUtils.addNonEmptyString(licenseJson.getJSONObject(k).optString("name"), licenses);
            }
            if (!licenses.isEmpty()) {
                return licenses;
            }
        }
        return Collections.emptyList();
    }

    private Map extractScancodeLicenseKeys(JSONObject segmentScancode) throws IOException {
        final Map keyValues = new HashMap<>();
        final JSONArray licenseJson = segmentScancode.optJSONArray("licenses");
        if (licenseJson != null) {
            for (int k = 0; k < licenseJson.length(); k++) {
                String key = licenseJson.getJSONObject(k).getString("key");
                Float value = licenseJson.getJSONObject(k).getFloat("score");
                if (StringUtils.notEmpty(key) && StringUtils.notEmpty(String.valueOf(value))) {
                    keyValues.put(key, value);
                }
            }
            if (!keyValues.isEmpty()) {
                return keyValues;
            }
        }
        return Collections.emptyMap();
    }

    private List extractFromMetascanResult(JSONArray array) {
        List list = new ArrayList<>();
        if (array != null) {
            for (int i = 0; i < array.length(); i++) {
                list.add(array.optString(i));
            }
        }
        return list;
    }

    private List extractVariables(JSONArray array) {
        List list = new ArrayList<>();
        if (array != null) {
            for (int i = 0; i < array.length(); i++) {
                //input
                JSONObject variable = array.optJSONObject(i);
                String license = variable.keySet().toArray()[0].toString();
                JSONObject values = variable.optJSONObject(license);

                //output
                Variables variableObj = new Variables();
                for (String s : values.keySet()) {
                    variableObj.putValues(s, values.optString(s));
                }
                variableObj.setLicense(license);
                list.add(variableObj);
            }
        }
        return list;
    }


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy