/*
 * 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.nifi.fingerprint;

import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.bundle.BundleCoordinate;
import org.apache.nifi.components.ConfigurableComponent;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.controller.FlowController;
import org.apache.nifi.controller.serialization.FlowEncodingVersion;
import org.apache.nifi.controller.serialization.FlowFromDOMFactory;
import org.apache.nifi.encrypt.PropertyEncryptor;
import org.apache.nifi.encrypt.SensitiveValueEncoder;
import org.apache.nifi.nar.ExtensionManager;
import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.util.BundleUtils;
import org.apache.nifi.util.DomUtils;
import org.apache.nifi.util.LoggingXmlParserErrorHandler;
import org.apache.nifi.web.api.dto.BundleDTO;
import org.apache.nifi.web.api.dto.ControllerServiceDTO;
import org.apache.nifi.web.api.dto.ReportingTaskDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.stream.Stream;

/**
 * <p>Creates a fingerprint of a flow.xml. The order of elements or attributes in the flow.xml does not influence the fingerprint generation.
 *
 * <p>Only items in the flow.xml that influence the processing of data are incorporated into the fingerprint.
 * Examples of items involved in the fingerprint are: processor IDs, processor relationships, and processor properties.
 * Examples of items not involved in the fingerprint are: items in the processor "comments" tabs, position information, flow controller settings, and counters.
 *
 * <p>The determination for making items into the fingerprint is whether we can
 * easily change the setting in order to inherit the cluster's flow.
 * For example, if the component has to be stopped to apply the change and started again,
 * then the item should be included in a fingerprint.
 */
public class FingerprintFactory {

    /*
     * Developer Note: This class should be changed with care and coordinated
     * with all classes that use fingerprinting.  Improper coordination may
     * lead to orphaning flow files, especially when flows are reloaded in a
     * clustered environment.
     */
    // no fingerprint value
    public static final String NO_VALUE = "NO_VALUE";

    static final String FLOW_CONFIG_XSD = "/FlowConfiguration.xsd";
    private static final String ENCRYPTED_VALUE_PREFIX = "enc{";
    private static final String ENCRYPTED_VALUE_SUFFIX = "}";
    private final PropertyEncryptor encryptor;
    private final DocumentBuilder flowConfigDocBuilder;
    private final ExtensionManager extensionManager;
    private final SensitiveValueEncoder sensitiveValueEncoder;

    private static final Logger logger = LoggerFactory.getLogger(FingerprintFactory.class);

    public FingerprintFactory(final PropertyEncryptor encryptor, final ExtensionManager extensionManager, final SensitiveValueEncoder sensitiveValueEncoder) {
        this.encryptor = encryptor;
        this.extensionManager = extensionManager;
        this.sensitiveValueEncoder = sensitiveValueEncoder;

        final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        final Schema schema;
        try {
            schema = schemaFactory.newSchema(FingerprintFactory.class.getResource(FLOW_CONFIG_XSD));
        } catch (final Exception e) {
            throw new RuntimeException("Failed to parse schema for file flow configuration.", e);
        }
        try {
            flowConfigDocBuilder = XmlUtils.createSafeDocumentBuilder(schema, true);
            flowConfigDocBuilder.setErrorHandler(new LoggingXmlParserErrorHandler("Flow Configuration", logger));
        } catch (final Exception e) {
            throw new RuntimeException("Failed to create document builder for flow configuration.", e);
        }
    }

    public FingerprintFactory(final PropertyEncryptor encryptor, final DocumentBuilder docBuilder, final ExtensionManager extensionManager, final SensitiveValueEncoder sensitiveValueEncoder) {
        this.encryptor = encryptor;
        this.flowConfigDocBuilder = docBuilder;
        this.extensionManager = extensionManager;
        this.sensitiveValueEncoder = sensitiveValueEncoder;
    }

    /**
     * Creates a fingerprint of a flow. The order of elements or attributes in the flow does not influence the fingerprint generation.
     * This method does not accept a FlowController, which means that Processors cannot be created in order to verify default property
     * values, etc. As a result, if Flow A and Flow B are fingerprinted and Flow B, for instance, contains a property with a default value
     * that is not present in Flow A, then the two will have different fingerprints.
     *
     * @param flowBytes the flow represented as bytes
     * @return a generated fingerprint
     * @throws FingerprintException if the fingerprint failed to be generated
     */
    public synchronized String createFingerprint(final byte[] flowBytes) throws FingerprintException {
        return createFingerprint(flowBytes, null);
    }

    /**
     * Creates a fingerprint of a flow. The order of elements or attributes in the flow does not influence the fingerprint generation.
     *
     * @param flowBytes  the flow represented as bytes
     * @param controller the controller
     * @return a generated fingerprint
     * @throws FingerprintException if the fingerprint failed to be generated
     */
    public synchronized String createFingerprint(final byte[] flowBytes, final FlowController controller) throws FingerprintException {
        return createFingerprint(parseFlow(flowBytes), controller);
    }

    /**
     * Creates a fingerprint from an XML document representing the flow.xml.
     *
     * @param flowDoc the DOM
     * @return the fingerprint
     */
    public synchronized String createFingerprint(final Document flowDoc, final FlowController controller) {
        if (flowDoc == null) {
            return "";
        }

        // builder to hold fingerprint state
        final StringBuilder fingerprintBuilder = new StringBuilder();

        // add flow controller fingerprint
        final Element flowControllerElem = flowDoc.getDocumentElement();
        if (flowControllerElem == null) {
            logger.warn("Unable to create fingerprint because no 'flowController' element found in XML.");
            return "";
        }

        final FlowEncodingVersion encodingVersion = FlowEncodingVersion.parse(flowControllerElem);

        addFlowControllerFingerprint(fingerprintBuilder, flowControllerElem, controller, encodingVersion);

        return fingerprintBuilder.toString();
    }

    /**
     * Parse the given flow.xml bytes into a Document instance.
     *
     * @param flow a flow
     * @return the DOM
     * @throws FingerprintException if the flow could not be parsed
     */
    private Document parseFlow(final byte[] flow) throws FingerprintException {
        if (flow == null || flow.length == 0) {
            return null;
        }

        try {
            return flowConfigDocBuilder.parse(new ByteArrayInputStream(flow));
        } catch (final SAXException | IOException ex) {
            throw new FingerprintException(ex);
        }
    }

    private StringBuilder addFlowControllerFingerprint(final StringBuilder builder, final Element flowControllerElem, final FlowController controller, final FlowEncodingVersion encodingVersion) {
        // registries
        final Element registriesElement = DomUtils.getChild(flowControllerElem, "registries");
        if (registriesElement == null) {
            builder.append("NO_VALUE");
        } else {
            final List<Element> flowRegistryElems = DomUtils.getChildElementsByTagName(registriesElement, "flowRegistry");
            if (flowRegistryElems.isEmpty()) {
                builder.append("NO_VALUE");
            } else {
                for (final Element flowRegistryElement : flowRegistryElems) {
                    addFlowRegistryFingerprint(builder, flowRegistryElement);
                }
            }
        }

        final Element contextsElement = DomUtils.getChild(flowControllerElem, "parameterContexts");
        if (contextsElement == null) {
            builder.append("NO_PARAMETER_CONTEXTS");
        } else {
            final List<Element> parameterContextElements = DomUtils.getChildElementsByTagName(contextsElement, "parameterContext");
            if (parameterContextElements.isEmpty()) {
                builder.append("NO_PARAMETER_CONTEXTS");
            } else {
                orderByChildElement(parameterContextElements, "id");

                for (final Element parameterContextElement : parameterContextElements) {
                    addParameterContext(builder, parameterContextElement);
                }
            }
        }

        // root group
        final Element rootGroupElem = (Element) DomUtils.getChildNodesByTagName(flowControllerElem, "rootGroup").item(0);
        addProcessGroupFingerprint(builder, rootGroupElem, encodingVersion);

        final Element controllerServicesElem = DomUtils.getChild(flowControllerElem, "controllerServices");
        if (controllerServicesElem != null) {
            final List<ControllerServiceDTO> serviceDtos = new ArrayList<>();
            for (final Element serviceElem : DomUtils.getChildElementsByTagName(controllerServicesElem, "controllerService")) {
                final ControllerServiceDTO dto = FlowFromDOMFactory.getControllerService(serviceElem, encryptor, encodingVersion);
                serviceDtos.add(dto);
            }

            Collections.sort(serviceDtos, new Comparator<ControllerServiceDTO>() {
                @Override
                public int compare(final ControllerServiceDTO o1, final ControllerServiceDTO o2) {
                    if (o1 == null && o2 == null) {
                        return 0;
                    }
                    if (o1 == null && o2 != null) {
                        return 1;
                    }
                    if (o1 != null && o2 == null) {
                        return -1;
                    }

                    return o1.getId().compareTo(o2.getId());
                }
            });

            for (final ControllerServiceDTO dto : serviceDtos) {
                addControllerServiceFingerprint(builder, dto);
            }
        }

        final Element reportingTasksElem = DomUtils.getChild(flowControllerElem, "reportingTasks");
        if (reportingTasksElem != null) {
            final List<ReportingTaskDTO> reportingTaskDtos = new ArrayList<>();
            for (final Element taskElem : DomUtils.getChildElementsByTagName(reportingTasksElem, "reportingTask")) {
                final ReportingTaskDTO dto = FlowFromDOMFactory.getReportingTask(taskElem, encryptor, encodingVersion);
                reportingTaskDtos.add(dto);
            }

            Collections.sort(reportingTaskDtos, new Comparator<ReportingTaskDTO>() {
                @Override
                public int compare(final ReportingTaskDTO o1, final ReportingTaskDTO o2) {
                    if (o1 == null && o2 == null) {
                        return 0;
                    }
                    if (o1 == null && o2 != null) {
                        return 1;
                    }
                    if (o1 != null && o2 == null) {
                        return -1;
                    }

                    return o1.getId().compareTo(o2.getId());
                }
            });

            for (final ReportingTaskDTO dto : reportingTaskDtos) {
                addReportingTaskFingerprint(builder, dto);
            }
        }

        return builder;
    }

    private void orderByChildElement(final List<Element> toSort, final String childTagName) {
        toSort.sort((a, b) -> {
            final String valueA = DomUtils.getChildText(a, childTagName);
            final String valueB = DomUtils.getChildText(b, childTagName);
            return valueA.compareTo(valueB);
        });
    }

    private StringBuilder addParameterContext(final StringBuilder builder, final Element parameterContextElement) {
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(parameterContextElement, "id"));
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(parameterContextElement, "name"));
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(parameterContextElement, "description"));

        final List<Element> parameterElements = DomUtils.getChildElementsByTagName(parameterContextElement, "parameter");
        if (parameterElements == null || parameterElements.isEmpty()) {
            builder.append("NO_PARAMETERS");
        } else {
            orderByChildElement(parameterElements, "name");

            for (final Element parameterElement : parameterElements) {
                addParameter(builder, parameterElement);
            }
        }

        return builder;
    }

    private void addParameter(final StringBuilder builder, final Element parameterElement) {
        Stream.of("name", "description", "sensitive").forEach(elementName -> appendFirstValue(builder, DomUtils.getChildNodesByTagName(parameterElement, elementName)));

        final String value = DomUtils.getChildText(parameterElement, "value");
        if (value == null) {
            builder.append("NO_VALUE");
            return;
        }

        // append value
        if (isEncrypted(value)) {
            // Get a secure, deterministic, loggable representation of this value
            builder.append(getLoggableRepresentationOfSensitiveValue(value));
        } else {
            builder.append(getValue(value, NO_VALUE));
        }

    }

    private StringBuilder addFlowRegistryFingerprint(final StringBuilder builder, final Element flowRegistryElement) {
        Stream.of("id", "name", "url", "description").forEach(elementName -> appendFirstValue(builder, DomUtils.getChildNodesByTagName(flowRegistryElement, elementName)));
        return builder;
    }

    StringBuilder addProcessGroupFingerprint(final StringBuilder builder, final Element processGroupElem, final FlowEncodingVersion encodingVersion) throws FingerprintException {
        // id
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processGroupElem, "id"));
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processGroupElem, "versionedComponentId"));
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processGroupElem, "parameterContextId"));
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processGroupElem, "flowfileConcurrency"));
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processGroupElem, "flowfileOutboundPolicy"));
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processGroupElem, "defaultFlowFileExpiration"));
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processGroupElem, "defaultBackPressureObjectThreshold"));
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processGroupElem, "defaultBackPressureDataSizeThreshold"));


        final Element versionControlInfo = DomUtils.getChild(processGroupElem, "versionControlInformation");
        if (versionControlInfo == null) {
            builder.append("NO_VERSION_CONTROL_INFORMATION");
        } else {
            appendFirstValue(builder, DomUtils.getChildNodesByTagName(versionControlInfo, "registryId"));
            appendFirstValue(builder, DomUtils.getChildNodesByTagName(versionControlInfo, "bucketId"));
            appendFirstValue(builder, DomUtils.getChildNodesByTagName(versionControlInfo, "flowId"));
            appendFirstValue(builder, DomUtils.getChildNodesByTagName(versionControlInfo, "version"));
        }

        // processors
        final List<Element> processorElems = DomUtils.getChildElementsByTagName(processGroupElem, "processor");
        processorElems.sort(getIdsComparator());
        for (final Element processorElem : processorElems) {
            addFlowFileProcessorFingerprint(builder, processorElem);
        }

        // input ports
        final NodeList inputPortElems = DomUtils.getChildNodesByTagName(processGroupElem, "inputPort");
        final List<Element> sortedInputPortElems = sortElements(inputPortElems, getIdsComparator());
        for (final Element inputPortElem : sortedInputPortElems) {
            addPortFingerprint(builder, inputPortElem);
        }

        // labels
        final NodeList labelElems = DomUtils.getChildNodesByTagName(processGroupElem, "label");
        final List<Element> sortedLabels = sortElements(labelElems, getIdsComparator());
        for (final Element labelElem : sortedLabels) {
            addLabelFingerprint(builder, labelElem);
        }

        // output ports
        final NodeList outputPortElems = DomUtils.getChildNodesByTagName(processGroupElem, "outputPort");
        final List<Element> sortedOutputPortElems = sortElements(outputPortElems, getIdsComparator());
        for (final Element outputPortElem : sortedOutputPortElems) {
            addPortFingerprint(builder, outputPortElem);
        }

        // process groups
        final NodeList nestedProcessGroupElems = DomUtils.getChildNodesByTagName(processGroupElem, "processGroup");
        final List<Element> sortedNestedProcessGroupElems = sortElements(nestedProcessGroupElems, getIdsComparator());
        for (final Element nestedProcessGroupElem : sortedNestedProcessGroupElems) {
            addProcessGroupFingerprint(builder, nestedProcessGroupElem, encodingVersion);
        }

        // remote process groups
        final NodeList remoteProcessGroupElems = DomUtils.getChildNodesByTagName(processGroupElem, "remoteProcessGroup");
        final List<Element> sortedRemoteProcessGroupElems = sortElements(remoteProcessGroupElems, getIdsComparator());
        for (final Element remoteProcessGroupElem : sortedRemoteProcessGroupElems) {
            addRemoteProcessGroupFingerprint(builder, remoteProcessGroupElem);
        }

        // connections
        final NodeList connectionElems = DomUtils.getChildNodesByTagName(processGroupElem, "connection");
        final List<Element> sortedConnectionElems = sortElements(connectionElems, getIdsComparator());
        for (final Element connectionElem : sortedConnectionElems) {
            addConnectionFingerprint(builder, connectionElem);
        }

        // funnel
        final NodeList funnelElems = DomUtils.getChildNodesByTagName(processGroupElem, "funnel");
        final List<Element> sortedFunnelElems = sortElements(funnelElems, getIdsComparator());
        for (final Element funnelElem : sortedFunnelElems) {
            addFunnelFingerprint(builder, funnelElem);
        }

        final NodeList controllerServiceElems = DomUtils.getChildNodesByTagName(processGroupElem, "controllerService");
        final List<Element> sortedControllerServiceElems = sortElements(controllerServiceElems, getIdsComparator());
        for (final Element controllerServiceElem : sortedControllerServiceElems) {
            final ControllerServiceDTO dto = FlowFromDOMFactory.getControllerService(controllerServiceElem, encryptor, encodingVersion);
            addControllerServiceFingerprint(builder, dto);
        }

        // add variables
        final NodeList variableElems = DomUtils.getChildNodesByTagName(processGroupElem, "variable");
        final List<Element> sortedVarList = sortElements(variableElems, getVariableNameComparator());
        for (final Element varElem : sortedVarList) {
            addVariableFingerprint(builder, varElem);
        }

        return builder;
    }

    private void addVariableFingerprint(final StringBuilder builder, final Element variableElement) {
        final String variableName = variableElement.getAttribute("name");
        final String variableValue = variableElement.getAttribute("value");
        builder.append(variableName).append("=").append(variableValue);
    }

    private StringBuilder addFlowFileProcessorFingerprint(final StringBuilder builder, final Element processorElem) throws FingerprintException {
        // id
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "id"));
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "versionedComponentId"));
        // class
        final NodeList childNodes = DomUtils.getChildNodesByTagName(processorElem, "class");
        final String className = childNodes.item(0).getTextContent();
        appendFirstValue(builder, childNodes);
        // annotation data
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "annotationData"));

        // get the bundle details if possible
        final BundleDTO bundle = FlowFromDOMFactory.getBundle(DomUtils.getChild(processorElem, "bundle"));
        addBundleFingerprint(builder, bundle);

        // max concurrent tasks
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "maxConcurrentTasks"));
        // scheduling period
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "schedulingPeriod"));
        // penalization period
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "penalizationPeriod"));
        // yield period
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "yieldPeriod"));
        // bulletin level
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "bulletinLevel"));
        // loss tolerant
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "lossTolerant"));
        // scheduling strategy
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "schedulingStrategy"));
        // execution node
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "executionNode"));
        // run duration nanos
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "runDurationNanos"));

        // get the temp instance of the Processor so that we know the default property values
        final BundleCoordinate coordinate = getCoordinate(className, bundle);
        final ConfigurableComponent configurableComponent = extensionManager.getTempComponent(className, coordinate);
        if (configurableComponent == null) {
            logger.warn("Unable to get Processor of type {}; its default properties will be fingerprinted instead of being ignored.", className);
        }

        // properties
        final NodeList propertyElems = DomUtils.getChildNodesByTagName(processorElem, "property");
        final List<Element> sortedPropertyElems = sortElements(propertyElems, getProcessorPropertiesComparator());
        for (final Element propertyElem : sortedPropertyElems) {
            final String propName = DomUtils.getChildElementsByTagName(propertyElem, "name").get(0).getTextContent();
            String propValue = getFirstValue(DomUtils.getChildNodesByTagName(propertyElem, "value"), null);
            addPropertyFingerprint(builder, configurableComponent, propName, propValue);
        }

        final NodeList autoTerminateElems = DomUtils.getChildNodesByTagName(processorElem, "autoTerminatedRelationship");
        final List<Element> sortedAutoTerminateElems = sortElements(autoTerminateElems, getElementTextComparator());
        for (final Element autoTerminateElem : sortedAutoTerminateElems) {
            builder.append(autoTerminateElem.getTextContent());
        }

        return builder;
    }

    private StringBuilder addPropertyFingerprint(final StringBuilder builder, final ConfigurableComponent component, final String propName, final String propValue) throws FingerprintException {
        // If we have a component to use, first determine if the value given is the default value for the specified property.
        // If so, we do not add the property to the fingerprint.
        // We do this because if a component is updated to add a new property, whenever we connect to the cluster, we have issues because
        // the Cluster Coordinator's flow comes from disk, where the flow.xml doesn't have the new property but our FlowController does have the new property.
        // This causes the fingerprints not to match. As a result, we just ignore default values, and this resolves the issue.

        if (component != null) {
            final PropertyDescriptor descriptor = component.getPropertyDescriptor(propName);
            if (descriptor != null && propValue != null && propValue.equals(descriptor.getDefaultValue())) {
                return builder;
            }
        }

        // check if there is a value
        if (propValue == null) {
            return builder;
        }

        // append name
        builder.append(propName).append("=");

        // append value
        if (isEncrypted(propValue)) {
            // Get a secure, deterministic, loggable representation of this value
            builder.append(getLoggableRepresentationOfSensitiveValue(propValue));
        } else {
            builder.append(getValue(propValue, NO_VALUE));
        }

        return builder;
    }

    /**
     * Returns a securely-derived, deterministic value from the provided encrypted property
     * value. This is because the flow fingerprint is displayed in the log if NiFi has
     * trouble inheriting a flow, so the sensitive value should not be disclosed through the
     * log. However, the equality or difference of the sensitive value can influence in the
     * inheritability of the flow, so it cannot be ignored completely.
     * <p>
     * The specific derivation process is unimportant as long as it is a salted,
     * cryptographically-secure hash function with an iteration cost sufficient for password
     * storage in other applications.
     *
     * @param encryptedPropertyValue the encrypted property value
     * @return a deterministic string value which represents this input but is safe to print in a log
     */
    private String getLoggableRepresentationOfSensitiveValue(String encryptedPropertyValue) {
        final String plaintextValue = decrypt(encryptedPropertyValue);
        return sensitiveValueEncoder.getEncoded(plaintextValue);
    }

    private StringBuilder addPortFingerprint(final StringBuilder builder, final Element portElem) throws FingerprintException {
        // id
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(portElem, "id"));
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(portElem, "versionedComponentId"));
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(portElem, "name"));
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(portElem, "allowRemoteAccess"));

        final NodeList userAccessControlNodeList = DomUtils.getChildNodesByTagName(portElem, "userAccessControl");
        if (userAccessControlNodeList == null || userAccessControlNodeList.getLength() == 0) {
            builder.append("NO_USER_ACCESS_CONTROL");
        } else {
            final List<String> sortedAccessControl = new ArrayList<>();
            for (int i = 0; i < userAccessControlNodeList.getLength(); i++) {
                sortedAccessControl.add(userAccessControlNodeList.item(i).getTextContent());
            }
            Collections.sort(sortedAccessControl);
            for (final String user : sortedAccessControl) {
                builder.append(user);
            }
        }

        final NodeList groupAccessControlNodeList = DomUtils.getChildNodesByTagName(portElem, "userAccessControl");
        if (groupAccessControlNodeList == null || groupAccessControlNodeList.getLength() == 0) {
            builder.append("NO_GROUP_ACCESS_CONTROL");
        } else {
            final List<String> sortedAccessControl = new ArrayList<>();
            for (int i = 0; i < groupAccessControlNodeList.getLength(); i++) {
                sortedAccessControl.add(groupAccessControlNodeList.item(i).getTextContent());
            }

            Collections.sort(sortedAccessControl);
            for (final String user : sortedAccessControl) {
                builder.append(user);
            }
        }

        return builder;
    }

    private StringBuilder addLabelFingerprint(final StringBuilder builder, final Element labelElem) {
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(labelElem, "id"));
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(labelElem, "versionedComponentId"));
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(labelElem, "value"));
        return builder;
    }

    private StringBuilder addRemoteProcessGroupFingerprint(final StringBuilder builder, final Element remoteProcessGroupElem) throws FingerprintException {

        for (String tagName : new String[]{"id", "versionedComponentId", "urls", "networkInterface", "timeout", "yieldPeriod",
                "transportProtocol", "proxyHost", "proxyPort", "proxyUser", "proxyPassword"}) {
            final String value = getFirstValue(DomUtils.getChildNodesByTagName(remoteProcessGroupElem, tagName));
            if (isEncrypted(value)) {
                builder.append(getLoggableRepresentationOfSensitiveValue(value));
            } else {
                builder.append(value);
            }
        }

        final NodeList inputPortList = DomUtils.getChildNodesByTagName(remoteProcessGroupElem, "inputPort");
        final NodeList outputPortList = DomUtils.getChildNodesByTagName(remoteProcessGroupElem, "outputPort");

        final Comparator<Element> portComparator = new Comparator<Element>() {
            @Override
            public int compare(final Element o1, final Element o2) {
                if (o1 == null && o2 == null) {
                    return 0;
                }
                if (o1 == null) {
                    return 1;
                }
                if (o2 == null) {
                    return -1;
                }

                NodeList nameList1 = DomUtils.getChildNodesByTagName(o1, "name");
                NodeList nameList2 = DomUtils.getChildNodesByTagName(o2, "name");

                if (nameList1.getLength() == 0 && nameList2.getLength() == 0) {
                    return 0;
                }
                if (nameList1.getLength() == 0) {
                    return 1;
                }
                if (nameList2.getLength() == 0) {
                    return -1;
                }

                return nameList1.item(0).getTextContent().compareTo(nameList2.item(0).getTextContent());
            }
        };

        final List<Element> sortedInputPorts = new ArrayList<>(inputPortList.getLength());
        for (int i = 0; i < inputPortList.getLength(); i++) {
            sortedInputPorts.add((Element) inputPortList.item(i));
        }
        Collections.sort(sortedInputPorts, portComparator);

        final List<Element> sortedOutputPorts = new ArrayList<>(outputPortList.getLength());
        for (int i = 0; i < outputPortList.getLength(); i++) {
            sortedOutputPorts.add((Element) outputPortList.item(i));
        }
        Collections.sort(sortedOutputPorts, portComparator);

        for (final Element inputPortElement : sortedInputPorts) {
            addRemoteGroupPortFingerprint(builder, inputPortElement);
        }

        for (final Element outputPortElement : sortedOutputPorts) {
            addRemoteGroupPortFingerprint(builder, outputPortElement);
        }

        return builder;
    }

    private StringBuilder addRemoteGroupPortFingerprint(final StringBuilder builder, final Element remoteGroupPortElement) {
        for (final String childName : new String[]{"id", "targetId", "versionedComponentId", "maxConcurrentTasks", "useCompression", "batchCount", "batchSize", "batchDuration"}) {
            appendFirstValue(builder, DomUtils.getChildNodesByTagName(remoteGroupPortElement, childName));
        }

        return builder;
    }


    private StringBuilder addConnectionFingerprint(final StringBuilder builder, final Element connectionElem) throws FingerprintException {
        // id
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "id"));
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "versionedComponentId"));
        // source id
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "sourceId"));
        // source group id
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "sourceGroupId"));
        // source type
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "sourceType"));
        // destination id
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "destinationId"));
        // destination group id
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "destinationGroupId"));
        // destination type
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "destinationType"));

        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "name"));

        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "loadBalanceStrategy"));
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "partitioningAttribute"));
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "loadBalanceCompression"));

        // relationships
        final NodeList relationshipElems = DomUtils.getChildNodesByTagName(connectionElem, "relationship");
        final List<Element> sortedRelationshipElems = sortElements(relationshipElems, getElementTextComparator());
        for (final Element relationshipElem : sortedRelationshipElems) {
            builder.append(getValue(relationshipElem, NO_VALUE));
        }

        return builder;
    }

    private StringBuilder addFunnelFingerprint(final StringBuilder builder, final Element funnelElem) throws FingerprintException {
        // id
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(funnelElem, "id"));
        appendFirstValue(builder, DomUtils.getChildNodesByTagName(funnelElem, "versionedComponentId"));
        return builder;
    }

    private void addControllerServiceFingerprint(final StringBuilder builder, final ControllerServiceDTO dto) {
        builder.append(dto.getId());
        builder.append(dto.getVersionedComponentId());
        builder.append(dto.getType());
        builder.append(dto.getName());

        addBundleFingerprint(builder, dto.getBundle());

        builder.append(dto.getComments());
        builder.append(dto.getAnnotationData());
        builder.append(dto.getState());

        // get the temp instance of the ControllerService so that we know the default property values
        final BundleCoordinate coordinate = getCoordinate(dto.getType(), dto.getBundle());
        final ConfigurableComponent configurableComponent = extensionManager.getTempComponent(dto.getType(), coordinate);
        if (configurableComponent == null) {
            logger.warn("Unable to get ControllerService of type {}; its default properties will be fingerprinted instead of being ignored.", dto.getType());
        }

        addPropertiesFingerprint(builder, configurableComponent, dto.getProperties());
    }

    private void addPropertiesFingerprint(final StringBuilder builder, final ConfigurableComponent component, final Map<String, String> properties) {
        if (properties == null) {
            builder.append("NO_PROPERTIES");
        } else {
            final SortedMap<String, String> sortedProps = new TreeMap<>(properties);
            for (final Map.Entry<String, String> entry : sortedProps.entrySet()) {
                addPropertyFingerprint(builder, component, entry.getKey(), entry.getValue());
            }
        }
    }

    private void addBundleFingerprint(final StringBuilder builder, final BundleDTO bundle) {
        if (bundle != null) {
            builder.append(bundle.getGroup());
            builder.append(bundle.getArtifact());
            builder.append(bundle.getVersion());
        } else {
            builder.append("MISSING_BUNDLE");
        }
    }

    private BundleCoordinate getCoordinate(final String type, final BundleDTO dto) {
        BundleCoordinate coordinate;
        try {
            coordinate = BundleUtils.getCompatibleBundle(extensionManager, type, dto);
        } catch (final IllegalStateException e) {
            if (dto == null) {
                coordinate = BundleCoordinate.UNKNOWN_COORDINATE;
            } else {
                coordinate = new BundleCoordinate(dto.getGroup(), dto.getArtifact(), dto.getVersion());
            }
        }
        return coordinate;
    }

    private void addReportingTaskFingerprint(final StringBuilder builder, final ReportingTaskDTO dto) {
        builder.append(dto.getId());
        builder.append(dto.getType());
        builder.append(dto.getName());

        addBundleFingerprint(builder, dto.getBundle());

        builder.append(dto.getComments());
        builder.append(dto.getSchedulingPeriod());
        builder.append(dto.getSchedulingStrategy());
        builder.append(dto.getAnnotationData());

        // get the temp instance of the ReportingTask so that we know the default property values
        final BundleCoordinate coordinate = getCoordinate(dto.getType(), dto.getBundle());
        final ConfigurableComponent configurableComponent = extensionManager.getTempComponent(dto.getType(), coordinate);
        if (configurableComponent == null) {
            logger.warn("Unable to get ReportingTask of type {}; its default properties will be fingerprinted instead of being ignored.", dto.getType());
        }

        addPropertiesFingerprint(builder, configurableComponent, dto.getProperties());
    }

    private Comparator<Element> getIdsComparator() {
        return new Comparator<Element>() {
            @Override
            public int compare(final Element e1, final Element e2) {
                // compare using processor ids
                final String e1Id = getFirstValue(DomUtils.getChildNodesByTagName(e1, "id"));
                final String e2Id = getFirstValue(DomUtils.getChildNodesByTagName(e2, "id"));
                return e1Id.compareTo(e2Id);
            }
        };
    }

    private Comparator<Element> getVariableNameComparator() {
        return new Comparator<Element>() {
            @Override
            public int compare(final Element e1, final Element e2) {
                if (e1 == null && e2 == null) {
                    return 0;
                }
                if (e1 == null) {
                    return 1;
                }
                if (e2 == null) {
                    return -1;
                }

                final String varName1 = e1.getAttribute("name");
                final String varName2 = e2.getAttribute("name");
                return varName1.compareTo(varName2);
            }
        };
    }

    private Comparator<Element> getProcessorPropertiesComparator() {
        return new Comparator<Element>() {
            @Override
            public int compare(final Element e1, final Element e2) {
                // combine the property name and value for the first required property
                final String e1PropName = getFirstValue(DomUtils.getChildNodesByTagName(e1, "name"));
                String e1PropValue = getFirstValue(DomUtils.getChildNodesByTagName(e1, "value"));
                if (isEncrypted(e1PropValue)) {
                    e1PropValue = getLoggableRepresentationOfSensitiveValue(e1PropValue);
                }
                final String e1CombinedValue = e1PropName + e1PropValue;

                // combine the property name and value for the second required property
                final String e2PropName = getFirstValue(DomUtils.getChildNodesByTagName(e2, "name"));
                String e2PropValue = getFirstValue(DomUtils.getChildNodesByTagName(e2, "value"));
                if (isEncrypted(e2PropValue)) {
                    e2PropValue = getLoggableRepresentationOfSensitiveValue(e2PropValue);
                }
                final String e2CombinedValue = e2PropName + e2PropValue;

                // compare the combined values
                return e1CombinedValue.compareTo(e2CombinedValue);
            }
        };
    }

    private Comparator<Element> getElementTextComparator() {
        return new Comparator<Element>() {
            @Override
            public int compare(final Element e1, final Element e2) {
                if (e2 == null) {
                    return -1;
                } else if (e1 == null) {
                    return 1;
                }

                return e1.getTextContent().compareTo(e2.getTextContent());
            }
        };
    }

    private List<Element> sortElements(final NodeList nodeList, final Comparator<Element> comparator) {

        final List<Element> result = new ArrayList<>();

        // add node list to sorted list
        for (int i = 0; i < nodeList.getLength(); i++) {
            result.add((Element) nodeList.item(i));
        }

        Collections.sort(result, comparator);

        return result;
    }

    private String getValue(final Node node) {
        return getValue(node, NO_VALUE);
    }

    private String getValue(final Node node, final String defaultValue) {
        final String value;
        if (node.getTextContent() == null || StringUtils.isBlank(node.getTextContent())) {
            value = defaultValue;
        } else {
            value = node.getTextContent().trim();
        }
        return value;
    }

    private String getValue(final String value, final String defaultValue) {
        if (StringUtils.isBlank(value)) {
            return defaultValue;
        } else {
            return value;
        }
    }

    private String getFirstValue(final NodeList nodeList) {
        return getFirstValue(nodeList, NO_VALUE);
    }

    private String getFirstValue(final NodeList nodeList, final String defaultValue) {
        final String value;
        if (nodeList == null || nodeList.getLength() == 0) {
            value = defaultValue;
        } else {
            value = getValue(nodeList.item(0));
        }
        return value;
    }

    private StringBuilder appendFirstValue(final StringBuilder builder, final NodeList nodeList) {
        return appendFirstValue(builder, nodeList, NO_VALUE);
    }

    private StringBuilder appendFirstValue(final StringBuilder builder, final NodeList nodeList, final String defaultValue) {
        return builder.append(getFirstValue(nodeList, defaultValue));
    }

    private boolean isEncrypted(final String value) {
        return (value.startsWith(ENCRYPTED_VALUE_PREFIX) && value.endsWith(ENCRYPTED_VALUE_SUFFIX));
    }

    private String decrypt(final String value) throws FingerprintException {
        final int decryptStartIdx = ENCRYPTED_VALUE_PREFIX.length();
        final int decryptEndIdx = value.length() - ENCRYPTED_VALUE_SUFFIX.length();
        return encryptor.decrypt(value.substring(decryptStartIdx, decryptEndIdx));
    }
}
