package de.mummeit.pmg.builder; import de.mummeit.pmg.api.model.integration.*; import java.util.ArrayList; import java.util.List; /** * A fluent builder for creating Permission Manager integrations. * This builder provides a type-safe way to create various types of integrations including: * - Domain integrations (create, update, delete) * - Permission integrations (create, update, delete) * - Role integrations (create, update, delete) * - Role-Permission relation integrations * * Example usage: * {@code * List> integrations = IntegrationBuilder.create() * .createDomain("my-domain", "My Domain") * .addPermission("read", "Read Permission") * .addRole("user", "User Role") * .assignPermissionsToRole("user", Arrays.asList("read")) * .build(); * } */ public class IntegrationBuilder { private final List> integrations = new ArrayList<>(); private String currentDomain; /** * Creates a new instance of the IntegrationBuilder. * * @return A new IntegrationBuilder instance */ public static IntegrationBuilder create() { return new IntegrationBuilder(); } /** * Selects a domain as the context for subsequent operations without creating an integration. * This is useful when you need to perform operations on an existing domain. * * @param name The name of the domain to select * @return This builder instance for method chaining */ public IntegrationBuilder selectDomain(String name) { this.currentDomain = name; return this; } /** * Creates a new domain integration with the specified name and description. * This also sets the domain context for subsequent operations. * * @param name The name of the domain * @param description The description of the domain * @return This builder instance for method chaining */ public IntegrationBuilder createDomain(String name, String description) { this.currentDomain = name; integrations.add(DomainIntegration.builder() .id(generateIntegrationId("domain", name, Integration.Action.create)) .action(Integration.Action.create) .data(DomainIntegration.Data.builder() .name(name) .description(description) .build()) .build()); return this; } /** * Updates an existing domain with a new name and/or description. * This also sets the domain context to the new name for subsequent operations. * * @param oldName The current name of the domain to update * @param newName The new name for the domain * @param description The new description for the domain * @return This builder instance for method chaining */ public IntegrationBuilder updateDomain(String oldName, String newName, String description) { integrations.add(DomainIntegration.builder() .id(generateIntegrationId("domain", oldName, Integration.Action.update)) .action(Integration.Action.update) .data(DomainIntegration.Data.builder() .name(newName) .oldName(oldName) .description(description) .build()) .build()); this.currentDomain = newName; return this; } /** * Deletes a domain. * * @param name The name of the domain to delete * @return This builder instance for method chaining */ public IntegrationBuilder deleteDomain(String name) { integrations.add(DomainIntegration.builder() .id(generateIntegrationId("domain", name, Integration.Action.delete)) .action(Integration.Action.delete) .data(DomainIntegration.Data.builder() .name(name) .build()) .build()); return this; } /** * Adds a new permission to the current domain. * * @param name The name of the permission * @param description The description of the permission * @return This builder instance for method chaining * @throws IllegalStateException if no domain context has been set */ public IntegrationBuilder addPermission(String name, String description) { validateDomain(); integrations.add(PermissionIntegration.builder() .id(generateIntegrationId("permission", currentDomain + ":" + name, Integration.Action.create)) .action(Integration.Action.create) .data(PermissionIntegration.Data.builder() .domain(currentDomain) .name(name) .description(description) .build()) .build()); return this; } /** * Updates an existing permission in the current domain. * * @param oldName The current name of the permission to update * @param newName The new name for the permission * @param description The new description for the permission * @return This builder instance for method chaining * @throws IllegalStateException if no domain context has been set */ public IntegrationBuilder updatePermission(String oldName, String newName, String description) { validateDomain(); integrations.add(PermissionIntegration.builder() .id(generateIntegrationId("permission", currentDomain + ":" + oldName, Integration.Action.update)) .action(Integration.Action.update) .data(PermissionIntegration.Data.builder() .domain(currentDomain) .name(newName) .oldName(oldName) .description(description) .build()) .build()); return this; } /** * Removes a permission from the current domain. * * @param name The name of the permission to remove * @return This builder instance for method chaining * @throws IllegalStateException if no domain context has been set */ public IntegrationBuilder removePermission(String name) { validateDomain(); integrations.add(PermissionIntegration.builder() .id(generateIntegrationId("permission", currentDomain + ":" + name, Integration.Action.delete)) .action(Integration.Action.delete) .data(PermissionIntegration.Data.builder() .domain(currentDomain) .name(name) .build()) .build()); return this; } /** * Adds a new role to the current domain. * * @param name The name of the role * @param description The description of the role * @return This builder instance for method chaining * @throws IllegalStateException if no domain context has been set */ public IntegrationBuilder addRole(String name, String description) { validateDomain(); integrations.add(RoleIntegration.builder() .id(generateIntegrationId("role", currentDomain + ":" + name, Integration.Action.create)) .action(Integration.Action.create) .data(RoleIntegration.Data.builder() .domain(currentDomain) .name(name) .description(description) .build()) .build()); return this; } /** * Updates an existing role in the current domain. * * @param oldName The current name of the role to update * @param newName The new name for the role * @param description The new description for the role * @return This builder instance for method chaining * @throws IllegalStateException if no domain context has been set */ public IntegrationBuilder updateRole(String oldName, String newName, String description) { validateDomain(); integrations.add(RoleIntegration.builder() .id(generateIntegrationId("role", currentDomain + ":" + oldName, Integration.Action.update)) .action(Integration.Action.update) .data(RoleIntegration.Data.builder() .domain(currentDomain) .name(newName) .oldName(oldName) .description(description) .build()) .build()); return this; } /** * Removes a role from the current domain. * * @param name The name of the role to remove * @return This builder instance for method chaining * @throws IllegalStateException if no domain context has been set */ public IntegrationBuilder removeRole(String name) { validateDomain(); integrations.add(RoleIntegration.builder() .id(generateIntegrationId("role", currentDomain + ":" + name, Integration.Action.delete)) .action(Integration.Action.delete) .data(RoleIntegration.Data.builder() .domain(currentDomain) .name(name) .build()) .build()); return this; } /** * Assigns a list of permissions to a role in the current domain. * * @param role The name of the role to assign permissions to * @param permissions List of permission names to assign to the role * @return This builder instance for method chaining * @throws IllegalStateException if no domain context has been set */ public IntegrationBuilder assignPermissionsToRole(String role, List permissions) { validateDomain(); String permissionList = String.join(",", permissions); integrations.add(RolePermissionRelationIntegration.builder() .id(generateIntegrationId("role-permissions", currentDomain + ":" + role + ":" + permissionList, Integration.Action.create)) .action(Integration.Action.create) .data(RolePermissionRelationIntegration.Data.builder() .domain(currentDomain) .role(role) .permissions(permissions) .build()) .build()); return this; } /** * Builds and returns the list of integrations created by this builder. * * @return A new list containing all the integrations created by this builder */ public List> build() { return new ArrayList<>(integrations); } /** * Validates that a domain context has been set by a previous domain operation. * * @throws IllegalStateException if no domain context has been set */ private void validateDomain() { if (currentDomain == null || currentDomain.trim().isEmpty()) { throw new IllegalStateException("No domain context set. Create, update, or select a domain first."); } } /** * Generates a deterministic integration ID based on the integration type, name, and action. * This ensures that the same integration will always have the same ID across different runs. * * @param type The type of integration (domain, permission, role, etc.) * @param name The unique name or identifier for this integration * @param action The action being performed * @return A deterministic ID string */ private String generateIntegrationId(String type, String name, Integration.Action action) { return String.format("%s:%s:%s", type, name, action.name().toLowerCase()); } }