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)
//
;
}
}