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

org.cyclonedx.AbstractBomGenerator Maven / Gradle / Ivy

Go to download

The CycloneDX core module provides a model representation of the BOM along with utilities to assist in creating, parsing, and validating BOMs.

There is a newer version: 10.0.0
Show newest version
/*
 * This file is part of CycloneDX Core (Java).
 *
 * 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.
 *
 * SPDX-License-Identifier: Apache-2.0
 * Copyright (c) Steve Springett. All Rights Reserved.
 */
package org.cyclonedx;

import org.cyclonedx.model.Attribute;
import org.cyclonedx.model.ExtensibleElement;
import org.cyclonedx.model.ExtensibleType;
import org.cyclonedx.model.Hash;
import org.cyclonedx.model.License;
import org.cyclonedx.model.LicenseChoice;
import org.cyclonedx.util.BomUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import javax.xml.XMLConstants;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.List;

abstract class AbstractBomGenerator extends CycloneDxSchema implements BomGenerator {

    Document doc;

    Element createElement(Node parent, String name) {
        final Element node = doc.createElement(name);
        parent.appendChild(node);
        return node;
    }

    Element createElementNS(Node parent, String namespace, String name) {
        final Element node = doc.createElementNS(namespace, name);
        parent.appendChild(node);
        return node;
    }

    Element createElement(Node parent, String name, Object value) {
        return createElement(parent, name, value, new Attribute[0]);
    }

    Element createElement(Node parent, String name, Object value, Attribute... attributes) {
        Element node = null;
        if (value != null || attributes.length > 0) {
            if (name.contains(":")) {
                node = doc.createElement(name);
            } else {
                node = doc.createElementNS(getSchemaVersion().getNamespace(), name);
            }
            for (Attribute attribute: attributes) {
                node.setAttribute(attribute.getKey(), attribute.getValue());
            }
            if (value != null) {
                node.appendChild(doc.createTextNode(value.toString()));
            }
            parent.appendChild(node);
        }
        return node;
    }

    void createHashesNode(Node parent, List hashes) {
        if (hashes != null && !hashes.isEmpty()) {
            final Element hashesNode = createElement(parent, "hashes");
            for (Hash hash : hashes) {
                createElement(hashesNode, "hash", hash.getValue(), new Attribute("alg", hash.getAlgorithm()));
            }
        }
    }

    void createLicenseNode(Node parent, LicenseChoice licenseChoice, boolean expressionSupport) {
        if (licenseChoice != null) {
            final Element licensesNode = doc.createElement("licenses");
            if (licenseChoice.getLicenses() != null) {
                parent.appendChild(licensesNode);
                for (License license : licenseChoice.getLicenses()) {
                    // Create individual license node
                    final Element licenseNode = doc.createElement("license");
                    if (license.getId() != null) {
                        final Element licenseIdNode = doc.createElement("id");
                        licenseIdNode.appendChild(doc.createTextNode(license.getId()));
                        licenseNode.appendChild(licenseIdNode);
                    } else if (license.getName() != null) {
                        final Element licenseNameNode = doc.createElement("name");
                        licenseNameNode.appendChild(doc.createTextNode(license.getName()));
                        licenseNode.appendChild(licenseNameNode);
                    }
                    if (Version.VERSION_10 != this.getSchemaVersion()) {
                        if (license.getLicenseText() != null && license.getLicenseText().getText() != null) {
                            final Element licenseTextNode = doc.createElement("text");
                            if (license.getLicenseText().getContentType() != null) {
                                licenseTextNode.setAttribute("content-type", license.getLicenseText().getContentType());
                            }
                            if (license.getLicenseText().getEncoding() != null) {
                                licenseTextNode.setAttribute("encoding", license.getLicenseText().getEncoding());
                                if ("base64".equals(license.getLicenseText().getEncoding())) {
                                    licenseTextNode.appendChild(doc.createTextNode(license.getLicenseText().getText()));
                                } else {
                                    licenseTextNode.appendChild(doc.createCDATASection(license.getLicenseText().getText()));
                                }
                            } else {
                                licenseTextNode.appendChild(doc.createCDATASection(license.getLicenseText().getText()));
                            }
                            licenseNode.appendChild(licenseTextNode);
                        }
                        if (BomUtils.validateUrlString(license.getUrl())) {
                            final Element licenseUrlNode = doc.createElement("url");
                            licenseUrlNode.appendChild(doc.createTextNode(license.getUrl()));
                            licenseNode.appendChild(licenseUrlNode);
                        }

                        processExtensions(licenseNode, license);
                    }
                    licensesNode.appendChild(licenseNode);
                }
            } else if (expressionSupport && licenseChoice.getExpression() != null) {
                createElement(licensesNode, "expression", stripBreaks(licenseChoice.getExpression()));
            }
        }
    }

    protected void processExtensions(final Node node, final ExtensibleElement extensibleElement) {
        if (extensibleElement != null && extensibleElement.getExtensibleTypes() != null) {
            for (final ExtensibleType t: extensibleElement.getExtensibleTypes()) {
                final Element e = createElementNS(node, t.getNamespace(), t.getName());
                if (t.getAttributes() != null) {
                    for (Attribute attr: t.getAttributes()) {
                        e.setAttribute(attr.getKey(), attr.getValue());
                    }
                }
                if (t.getValue() != null) {
                    e.appendChild(doc.createTextNode(t.getValue()));
                } else if (t.getExtensibleTypes() != null) {
                    for (final ExtensibleType childType: t.getExtensibleTypes()) {
                        final Element childNode = createElementNS(e, childType.getNamespace(), childType.getName());
                        processExtensions(childNode, childType);
                    }
                }
            }
        }
    }

    Element createRootElement(String name, Object value, Attribute... attributes) {
        Element node = null;
        if (value != null || attributes.length > 0) {
            node = doc.createElementNS(getSchemaVersion().getNamespace(), name);
            for (Attribute attribute: attributes) {
                node.setAttribute(attribute.getKey(), attribute.getValue());
            }
            if (value != null) {
                node.appendChild(doc.createTextNode(value.toString()));
            }
            doc.appendChild(node);
        }
        return node;
    }

    static String stripBreaks(String in) {
        if (in == null) {
            return null;
        }
        return in.trim().replace("\r\n", " ").replace("\n", " ").replace("\t", " ").replace("\r", " ").replaceAll(" +", " ");
    }

    /**
     * Creates a text representation of a CycloneDX BoM Document.
     * @return a String of the BoM
     * @throws TransformerException an TransformerException
     * @since 1.1.0
     */
    public String toXmlString() throws TransformerException {
        if (doc == null) {
            return null;
        }
        final DOMSource domSource = new DOMSource(doc);
        final StringWriter writer = new StringWriter();
        final StreamResult result = new StreamResult(writer);
        final TransformerFactory tf = TransformerFactory.newInstance();
        tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
        final Transformer transformer = tf.newTransformer();
        transformer.setOutputProperty(OutputKeys.ENCODING, StandardCharsets.UTF_8.name());
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "yes");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
        transformer.transform(domSource, result);

        return writer.toString();
    }

    /**
     * Creates a text representation of a CycloneDX BoM Document. This method
     * calls {@link #toXmlString()} and will return null if {@link #toXmlString()}
     * throws an exception. Its preferred to call {@link #toXmlString()} directly
     * so that exceptions can be caught.
     * @return a String of the BoM
     * @since 1.1.0
     */
    @Override
    public String toString() {
        try {
            return toXmlString();
        } catch (TransformerException e) {
            return "";
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy