class ConsistencyChecker {

    public void checkNamespaceUri(@NonNull DefinitionsChildId id) {
        Objects.requireNonNull(id);

        String uriStr = id.getNamespace().getDecoded();
        if (!uriStr.trim().equals(uriStr)) {
            printAndAddError(id, "Namespace starts or ends with white spaces");
        }
        URI uri;
        try {
            uri = new URI(uriStr);
        } catch (URISyntaxException e) {
            LOGGER.debug("Invalid URI", e);
            printAndAddError(id, "Invalid URI: " + e.getMessage());
            return;
        }
        if (!uri.isAbsolute()) {
            printAndAddError(id, "URI is relative");
        }
        if ((uriStr.startsWith("http://www.opentosca.org/") && (!uriStr.toLowerCase().equals(uriStr)))) {
            // URI is not lowercase
            // There are some special URIs, which are OK
            String[] splitUri = uriStr.split("/");
            String lastElement = splitUri[splitUri.length - 1];
            String uriStrWithoutLastElement = uriStr.substring(0, (uriStr.length() - lastElement.length()));
            if (!(id.getXmlId().toString().startsWith(lastElement)) || (!uriStrWithoutLastElement.toLowerCase().equals(uriStrWithoutLastElement))) {
                printAndAddError(id, "opentosca URI is not lowercase");
            }
        }
        if (uriStr.endsWith("/")) {
            printAndAddError(id, "URI ends with a slash");
        }
        if (uriStr.contains(ARTEFACT_BE)) {
            printAndAddError(id, "artifact is spelled with i in American English, not artefact as in British English");
        }
        // We could just check OpenTOSCA namespace rule examples. However, this would be too strict
        // Here, the idea is to check whether a string of another (!) id class appers in the namespace
        // If this is the case, the namespace is not consistent
        // For instance, a node type residing in the namespace: http://servicetemplates.example.org should not exist.
        boolean namespaceUriContainsDifferentType = DefinitionsChildId.ALL_TOSCA_COMPONENT_ID_CLASSES.stream()
            .filter(definitionsChildIdClass -> !definitionsChildIdClass.isAssignableFrom(id.getClass()))
            // we have the issue that nodetypeimplementation also contains nodetype
            // we do the quick hack and check for plural s and /
            .flatMap(definitionsChildIdClass -> {
                final String lowerCaseIdClass = Util.getTypeForComponentId(definitionsChildIdClass).toLowerCase();
                return Stream.of(lowerCaseIdClass + "s", lowerCaseIdClass + "/");
            })
            .anyMatch(definitionsChildName -> uriStr.contains(definitionsChildName));
        if (namespaceUriContainsDifferentType) {
            if ((id instanceof ServiceTemplateId) && (id.getNamespace().getDecoded().contains("compliance"))) {
                // special case, becaue TComplianceRule models a service template, but Compliance Rules are treated as Service Template during modeling
                // example: class org.eclipse.winery.common.ids.definitions.ServiceTemplateId / {http://www.compliance.opentosca.org/compliancerules}Satisfied_Compliance_Rule_Example_w1
            } else {
                printAndAddError(id, "Namespace URI contains tosca definitions name from other type. E.g., Namespace is ...servicetemplates..., but the type is an artifact template");
            }
        }
    }

    public  ConsistencyChecker(@NonNull ConsistencyCheckerConfiguration configuration);
    public  ConsistencyChecker(@NonNull ConsistencyCheckerConfiguration configuration,
                              @NonNull ConsistencyCheckerProgressListener consistencyCheckerProgressListener);

}