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

com.sap.cloud.security.ams.dcl.client.dcn.DcnSchemaBuilderImpl Maven / Gradle / Ivy

The newest version!
/************************************************************************
 * © 2019-2024 SAP SE or an SAP affiliate company. All rights reserved. *
 ************************************************************************/
package com.sap.cloud.security.ams.dcl.client.dcn;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;

import com.sap.cloud.security.ams.dcl.client.el.AttributeName;
import com.sap.cloud.security.ams.dcl.client.el.QualifiedName;
import com.sap.cloud.security.ams.dcl.client.language.DataControlLanguageNames;

class DcnSchemaBuilderImpl implements DcnSchemaBuilder {

    static final String DCN_SCHEMA_NAME = "schema";

    private static final QualifiedName ROOT_SCHEMA = QualifiedName.create(DCN_SCHEMA_NAME);
    private final Schema schema;
    private final List structureNesting = new ArrayList<>();
    private final Structure structure = new StructureImpl();

    DcnSchemaBuilderImpl() {
        this(true);
    }

    DcnSchemaBuilderImpl(QualifiedName dclPackage, String tenant) {
        this(false);

        Objects.requireNonNull(dclPackage, "dclPackage must not be null");
        if (dclPackage.isEmpty()) {
            throw new IllegalArgumentException("dclPackage must not be EMPTY.");
        }
        Objects.requireNonNull(tenant, "tenant must not be null");
        if (tenant.isEmpty()) {
            throw new IllegalArgumentException("tenant must not be EMPTY.");
        }
        schema.qualifiedName(dclPackage.append(DCN_SCHEMA_NAME));
        schema.tenant(tenant);
    }

    private DcnSchemaBuilderImpl(boolean withDCL) {
        schema = new Schema();
        schema.qualifiedName(ROOT_SCHEMA);
        schema.tenant("");
        SchemaAttribute definition = new SchemaAttribute();
        definition.attributeName(AttributeName.EMPTY);
        definition.type(DataType.Structure);
        schema.definition(definition);
        structureNesting.add(definition);
        if (withDCL) {
            addDCLDefault();
        }
    }

    @Override
    public DcnSchemaBuilder attribute(AttributeName attName, DataType type) {
        createSchemaAttribute(attName, type, null);
        return this;
    }

    @Override
    public DcnSchemaBuilder attribute(AttributeName attName, DataType type, Consumer c) {
        createSchemaAttribute(attName, type, c);
        return this;
    }

    @Override
    public Structure app() {
        return resetNavigation(DataControlLanguageNames.APP_SECTION_KEY);
    }

    @Override
    public Structure env() {
        return resetNavigation(DataControlLanguageNames.ENV_SECTION_KEY);
    }

    @Override
    public Schema build() {
        return schema;
    }

    public SchemaAttribute current() {
        return structureNesting.get(structureNesting.size() - 1);
    }

    private Structure resetNavigation(String key) {
        for (int i = structureNesting.size() - 1; i > 0; --i) {
            structureNesting.remove(i);
        }
        return structure.structure(key);
    }

    private class StructureImpl implements Structure {

        @Override
        public Structure structure(String name) {
            return grantSchemaAttribute(name, DataType.Structure, null);
        }

        @Override
        public Structure attribute(String name, DataType type) {
            if (DataType.Structure.equals(type)) {
                throw new IllegalArgumentException("Structures need to be added by structure(...).");
            }
            return grantSchemaAttribute(name, type, null);
        }

        @Override
        public Structure attribute(String name, DataType type, Consumer c) {
            if (DataType.Structure.equals(type)) {
                throw new IllegalArgumentException("Structures need to be added by structure(...).");
            }
            return grantSchemaAttribute(name, type, c);
        }

        @Override
        public Structure end() {
            if (structureNesting.size() == 1) {
                throw new IllegalStateException("Cannot close root");
            }
            structureNesting.remove(structureNesting.size() - 1);
            return this;
        }

        @Override
        public DcnSchemaBuilder builder() {
            return DcnSchemaBuilderImpl.this;
        }

        private Structure grantSchemaAttribute(String name, DataType type, Consumer c) {
            if (name == null || name.isEmpty()) {
                throw new IllegalArgumentException("Name must not be null or empty");
            }
            SchemaAttribute parent = current();
            Map nested = parent.nested();
            if (nested == null) {
                nested = new HashMap<>();
                parent.nested(nested);
            }
            SchemaAttribute result;

            result = nested.get(name);
            if (result != null) {
                if (!type.equals(result.type())) {
                    throw new IllegalStateException("Structure mismatch");
                }
            } else {
                result = new SchemaAttribute();
                result.attributeName(parent.attributeName().append(name));
                result.type(type);
                nested.put(name, result);
            }
            if (c != null) {
                c.accept(result);
            }
            if (DataType.Structure.equals(type)) {
                structureNesting.add(result);
            }
            return this;
        }
    }

    @SuppressWarnings("java:S3776")
    private void createSchemaAttribute(AttributeName attName, DataType type, Consumer c) {
        SchemaAttribute current = schema.definition();
        if (attName == null || attName.isEmpty()) {
            throw new IllegalArgumentException("Attribute name must not be null or empty");
        }

        for (int i = 0, end = attName.size() - 1; i <= end; ++i) {
            String segment = attName.getSegment(i);
            Map nested = current.nested();
            DataType expectedType = i == end ? type : DataType.Structure;
            if (nested == null) {
                nested = new HashMap<>();
                current.nested(nested);
            } else {
                current = nested.get(segment);
                if (current != null) {
                    if (!expectedType.equals(current.type())) {
                        throw new IllegalStateException("Structure mismatch");
                    }
                    continue;
                }
            }
            current = new SchemaAttribute();
            current.attributeName(attName.subName(0, i + 1));
            current.type(expectedType);
            nested.put(segment, current);
        }
        if (c != null) {
            c.accept(current);
        }
    }

    private Structure dcl() {
        return resetNavigation(DataControlLanguageNames.DCL_SECTION_KEY);
    }

    private void addDCLDefault() {
        dcl()
                .attribute(DataControlLanguageNames.DCL_ACTION_KEY, DataType.String)
                .attribute(DataControlLanguageNames.DCL_RESOURCE_KEY, DataType.String)
                .attribute(DataControlLanguageNames.DCL_TENANT_KEY, DataType.String)
                .attribute(DataControlLanguageNames.DCL_POLICIES_KEY, DataType.StringArray)
                .attribute(DataControlLanguageNames.DCL_SCOPE_FILTER_KEY, DataType.String)
                .attribute(DataControlLanguageNames.DCL_PRINCIPAL_TO_POLICIES_KEY, DataType.StringArray)
        //
        ;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy