Ajay Yadav commited on
Commit
5cfe5c4
·
1 Parent(s): fc2c890

Initial deployment of da-policyengine-dev

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. Dockerfile +27 -0
  2. README.md +33 -5
  3. build.gradle.kts +16 -0
  4. src/main/docker/Dockerfile +23 -0
  5. src/main/docker/Dockerfile.alpine-jlink +43 -0
  6. src/main/docker/Dockerfile.layered +34 -0
  7. src/main/docker/Dockerfile.native +20 -0
  8. src/main/java/com/dalab/policyengine/DaPolicyEngineApplication.java +37 -0
  9. src/main/java/com/dalab/policyengine/common/ConflictException.java +11 -0
  10. src/main/java/com/dalab/policyengine/common/ResourceNotFoundException.java +15 -0
  11. src/main/java/com/dalab/policyengine/config/OpenAPIConfiguration.java +27 -0
  12. src/main/java/com/dalab/policyengine/config/SecurityConfiguration.java +44 -0
  13. src/main/java/com/dalab/policyengine/dto/EventAnalyticsDTO.java +349 -0
  14. src/main/java/com/dalab/policyengine/dto/EventStreamDTO.java +216 -0
  15. src/main/java/com/dalab/policyengine/dto/EventSubscriptionInputDTO.java +229 -0
  16. src/main/java/com/dalab/policyengine/dto/EventSubscriptionOutputDTO.java +343 -0
  17. src/main/java/com/dalab/policyengine/dto/PolicyDraftActionDTO.java +268 -0
  18. src/main/java/com/dalab/policyengine/dto/PolicyDraftInputDTO.java +227 -0
  19. src/main/java/com/dalab/policyengine/dto/PolicyDraftOutputDTO.java +412 -0
  20. src/main/java/com/dalab/policyengine/dto/PolicyEvaluationOutputDTO.java +92 -0
  21. src/main/java/com/dalab/policyengine/dto/PolicyEvaluationRequestDTO.java +32 -0
  22. src/main/java/com/dalab/policyengine/dto/PolicyEvaluationSummaryDTO.java +64 -0
  23. src/main/java/com/dalab/policyengine/dto/PolicyImpactRequestDTO.java +211 -0
  24. src/main/java/com/dalab/policyengine/dto/PolicyImpactResponseDTO.java +376 -0
  25. src/main/java/com/dalab/policyengine/dto/PolicyInputDTO.java +80 -0
  26. src/main/java/com/dalab/policyengine/dto/PolicyOutputDTO.java +111 -0
  27. src/main/java/com/dalab/policyengine/dto/PolicyRuleDTO.java +72 -0
  28. src/main/java/com/dalab/policyengine/dto/PolicySummaryDTO.java +73 -0
  29. src/main/java/com/dalab/policyengine/event/PolicyActionEvent.java +102 -0
  30. src/main/java/com/dalab/policyengine/kafka/consumer/AssetChangeConsumer.java +50 -0
  31. src/main/java/com/dalab/policyengine/kafka/consumer/AssetChangeEventListener.java +61 -0
  32. src/main/java/com/dalab/policyengine/kafka/producer/PolicyActionKafkaProducer.java +54 -0
  33. src/main/java/com/dalab/policyengine/kafka/producer/PolicyActionProducer.java +42 -0
  34. src/main/java/com/dalab/policyengine/mapper/PolicyDraftMapper.java +372 -0
  35. src/main/java/com/dalab/policyengine/mapper/PolicyMapper.java +141 -0
  36. src/main/java/com/dalab/policyengine/model/EventRule.java +226 -0
  37. src/main/java/com/dalab/policyengine/model/EventSeverity.java +31 -0
  38. src/main/java/com/dalab/policyengine/model/EventSubscription.java +339 -0
  39. src/main/java/com/dalab/policyengine/model/EventSubscriptionStatus.java +26 -0
  40. src/main/java/com/dalab/policyengine/model/EventType.java +123 -0
  41. src/main/java/com/dalab/policyengine/model/Policy.java +171 -0
  42. src/main/java/com/dalab/policyengine/model/PolicyDraft.java +495 -0
  43. src/main/java/com/dalab/policyengine/model/PolicyDraftStatus.java +47 -0
  44. src/main/java/com/dalab/policyengine/model/PolicyEvaluation.java +119 -0
  45. src/main/java/com/dalab/policyengine/model/PolicyEvaluationStatus.java +9 -0
  46. src/main/java/com/dalab/policyengine/model/PolicyRule.java +137 -0
  47. src/main/java/com/dalab/policyengine/model/PolicyStatus.java +6 -0
  48. src/main/java/com/dalab/policyengine/repository/EventRuleRepository.java +86 -0
  49. src/main/java/com/dalab/policyengine/repository/EventSubscriptionRepository.java +100 -0
  50. src/main/java/com/dalab/policyengine/repository/PolicyDraftRepository.java +169 -0
Dockerfile ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM openjdk:21-jdk-slim
2
+
3
+ WORKDIR /app
4
+
5
+ # Install required packages
6
+ RUN apt-get update && apt-get install -y \
7
+ curl \
8
+ wget \
9
+ && rm -rf /var/lib/apt/lists/*
10
+
11
+ # Copy application files
12
+ COPY . .
13
+
14
+ # Build application (if build.gradle.kts exists)
15
+ RUN if [ -f "build.gradle.kts" ]; then \
16
+ ./gradlew build -x test; \
17
+ fi
18
+
19
+ # Expose port
20
+ EXPOSE 8080
21
+
22
+ # Health check
23
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
24
+ CMD curl -f http://localhost:8080/actuator/health || exit 1
25
+
26
+ # Run application
27
+ CMD ["java", "-jar", "build/libs/da-policyengine.jar"]
README.md CHANGED
@@ -1,10 +1,38 @@
1
  ---
2
- title: Da Policyengine Dev
3
- emoji:
4
  colorFrom: blue
5
- colorTo: red
6
  sdk: docker
7
- pinned: false
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: da-policyengine (dev)
3
+ emoji: 🔧
4
  colorFrom: blue
5
+ colorTo: green
6
  sdk: docker
7
+ app_port: 8080
8
  ---
9
 
10
+ # da-policyengine - dev Environment
11
+
12
+ This is the da-policyengine microservice deployed in the dev environment.
13
+
14
+ ## Features
15
+
16
+ - RESTful API endpoints
17
+ - Health monitoring via Actuator
18
+ - JWT authentication integration
19
+ - PostgreSQL database connectivity
20
+
21
+ ## API Documentation
22
+
23
+ Once deployed, API documentation will be available at:
24
+ - Swagger UI: https://huggingface.co/spaces/dalabsai/da-policyengine-dev/swagger-ui.html
25
+ - Health Check: https://huggingface.co/spaces/dalabsai/da-policyengine-dev/actuator/health
26
+
27
+ ## Environment
28
+
29
+ - **Environment**: dev
30
+ - **Port**: 8080
31
+ - **Java Version**: 21
32
+ - **Framework**: Spring Boot
33
+
34
+ ## Deployment
35
+
36
+ This service is automatically deployed via the DALab CI/CD pipeline.
37
+
38
+ Last updated: 2025-06-16 23:40:00
build.gradle.kts ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // da-policyengine inherits common configuration from parent build.gradle.kts
2
+ // This build file adds policy-engine-specific dependencies
3
+
4
+ dependencies {
5
+ // Easy Rules engine for policy evaluation
6
+ implementation("org.jeasy:easy-rules-core:4.1.0")
7
+ implementation("org.jeasy:easy-rules-mvel:4.1.0")
8
+
9
+ // Additional dependencies specific to da-policyengine
10
+ implementation("org.springframework.cloud:spring-cloud-starter-openfeign:4.1.1")
11
+ }
12
+
13
+ // Configure main application class
14
+ configure<org.springframework.boot.gradle.dsl.SpringBootExtension> {
15
+ mainClass.set("com.dalab.policyengine.DaPolicyEngineApplication")
16
+ }
src/main/docker/Dockerfile ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Ultra-lean container using Google Distroless
2
+ # Expected final size: ~120-180MB (minimal base + JRE + JAR only)
3
+
4
+ FROM gcr.io/distroless/java21-debian12:nonroot
5
+
6
+ # Set working directory
7
+ WORKDIR /app
8
+
9
+ # Copy JAR file
10
+ COPY build/libs/da-policyengine.jar app.jar
11
+
12
+ # Expose standard Spring Boot port
13
+ EXPOSE 8080
14
+
15
+ # Run application (distroless has no shell, so use exec form)
16
+ ENTRYPOINT ["java", \
17
+ "-XX:+UseContainerSupport", \
18
+ "-XX:MaxRAMPercentage=75.0", \
19
+ "-XX:+UseG1GC", \
20
+ "-XX:+UseStringDeduplication", \
21
+ "-Djava.security.egd=file:/dev/./urandom", \
22
+ "-Dspring.backgroundpreinitializer.ignore=true", \
23
+ "-jar", "app.jar"]
src/main/docker/Dockerfile.alpine-jlink ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Ultra-minimal Alpine + Custom JRE
2
+ # Expected size: ~120-160MB
3
+
4
+ # Stage 1: Create custom JRE with only needed modules
5
+ FROM eclipse-temurin:21-jdk-alpine as jre-builder
6
+ WORKDIR /app
7
+
8
+ # Analyze JAR to find required modules
9
+ COPY build/libs/*.jar app.jar
10
+ RUN jdeps --ignore-missing-deps --print-module-deps app.jar > modules.txt
11
+
12
+ # Create minimal JRE with only required modules
13
+ RUN jlink \
14
+ --add-modules $(cat modules.txt),java.logging,java.xml,java.sql,java.naming,java.desktop,java.management,java.security.jgss,java.instrument \
15
+ --strip-debug \
16
+ --no-man-pages \
17
+ --no-header-files \
18
+ --compress=2 \
19
+ --output /custom-jre
20
+
21
+ # Stage 2: Production image
22
+ FROM alpine:3.19
23
+ RUN apk add --no-cache tzdata && \
24
+ addgroup -g 1001 -S appgroup && \
25
+ adduser -u 1001 -S appuser -G appgroup
26
+
27
+ # Copy custom JRE
28
+ COPY --from=jre-builder /custom-jre /opt/java
29
+ ENV JAVA_HOME=/opt/java
30
+ ENV PATH="$JAVA_HOME/bin:$PATH"
31
+
32
+ WORKDIR /app
33
+ COPY build/libs/*.jar app.jar
34
+ RUN chown appuser:appgroup app.jar
35
+
36
+ USER appuser
37
+ EXPOSE 8080
38
+
39
+ ENTRYPOINT ["java", \
40
+ "-XX:+UseContainerSupport", \
41
+ "-XX:MaxRAMPercentage=70.0", \
42
+ "-XX:+UseG1GC", \
43
+ "-jar", "app.jar"]
src/main/docker/Dockerfile.layered ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Ultra-optimized layered build using Distroless
2
+ # Expected size: ~180-220MB with better caching
3
+
4
+ FROM gcr.io/distroless/java21-debian12:nonroot as base
5
+
6
+ # Stage 1: Extract JAR layers for optimal caching
7
+ FROM eclipse-temurin:21-jdk-alpine as extractor
8
+ WORKDIR /app
9
+ COPY build/libs/*.jar app.jar
10
+ RUN java -Djarmode=layertools -jar app.jar extract
11
+
12
+ # Stage 2: Production image with extracted layers
13
+ FROM base
14
+ WORKDIR /app
15
+
16
+ # Copy layers in dependency order (best caching)
17
+ COPY --from=extractor /app/dependencies/ ./
18
+ COPY --from=extractor /app/spring-boot-loader/ ./
19
+ COPY --from=extractor /app/snapshot-dependencies/ ./
20
+ COPY --from=extractor /app/application/ ./
21
+
22
+ EXPOSE 8080
23
+
24
+ # Optimized JVM settings for micro-containers
25
+ ENTRYPOINT ["java", \
26
+ "-XX:+UseContainerSupport", \
27
+ "-XX:MaxRAMPercentage=70.0", \
28
+ "-XX:+UseG1GC", \
29
+ "-XX:+UseStringDeduplication", \
30
+ "-XX:+CompactStrings", \
31
+ "-Xshare:on", \
32
+ "-Djava.security.egd=file:/dev/./urandom", \
33
+ "-Dspring.backgroundpreinitializer.ignore=true", \
34
+ "org.springframework.boot.loader.JarLauncher"]
src/main/docker/Dockerfile.native ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # GraalVM Native Image - Ultra-fast startup, tiny size
2
+ # Expected size: ~50-80MB, startup <100ms
3
+ # Note: Requires native compilation support in Spring Boot
4
+
5
+ # Stage 1: Native compilation
6
+ FROM ghcr.io/graalvm/graalvm-ce:ol9-java21 as native-builder
7
+ WORKDIR /app
8
+
9
+ # Install native-image
10
+ RUN gu install native-image
11
+
12
+ # Copy source and build native executable
13
+ COPY . .
14
+ RUN ./gradlew nativeCompile
15
+
16
+ # Stage 2: Minimal runtime
17
+ FROM scratch
18
+ COPY --from=native-builder /app/build/native/nativeCompile/app /app
19
+ EXPOSE 8080
20
+ ENTRYPOINT ["/app"]
src/main/java/com/dalab/policyengine/DaPolicyEngineApplication.java ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine;
2
+
3
+ import org.springframework.boot.SpringApplication;
4
+ import org.springframework.boot.autoconfigure.SpringBootApplication;
5
+ import org.springframework.cloud.openfeign.EnableFeignClients;
6
+ import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
7
+ import org.springframework.kafka.annotation.EnableKafka;
8
+ import org.springframework.scheduling.annotation.EnableAsync;
9
+ import org.springframework.scheduling.annotation.EnableScheduling;
10
+
11
+ /**
12
+ * Main application class for DALab Policy Engine Service.
13
+ *
14
+ * This service handles:
15
+ * - Policy management and evaluation
16
+ * - Easy Rules engine integration
17
+ * - Kafka event processing for asset changes
18
+ * - Policy action execution and notifications
19
+ *
20
+ * @author DALab Development Team
21
+ * @since 1.0.0
22
+ */
23
+ @SpringBootApplication(scanBasePackages = {
24
+ "com.dalab.policyengine",
25
+ "com.dalab.discovery.common.security" // Include common security utils
26
+ })
27
+ @EnableJpaRepositories
28
+ @EnableFeignClients
29
+ @EnableKafka
30
+ @EnableAsync
31
+ @EnableScheduling
32
+ public class DaPolicyEngineApplication {
33
+
34
+ public static void main(String[] args) {
35
+ SpringApplication.run(DaPolicyEngineApplication.class, args);
36
+ }
37
+ }
src/main/java/com/dalab/policyengine/common/ConflictException.java ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.common;
2
+
3
+ import org.springframework.http.HttpStatus;
4
+ import org.springframework.web.bind.annotation.ResponseStatus;
5
+
6
+ @ResponseStatus(HttpStatus.CONFLICT)
7
+ public class ConflictException extends RuntimeException {
8
+ public ConflictException(String message) {
9
+ super(message);
10
+ }
11
+ }
src/main/java/com/dalab/policyengine/common/ResourceNotFoundException.java ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.common;
2
+
3
+ import org.springframework.http.HttpStatus;
4
+ import org.springframework.web.bind.annotation.ResponseStatus;
5
+
6
+ @ResponseStatus(HttpStatus.NOT_FOUND)
7
+ public class ResourceNotFoundException extends RuntimeException {
8
+ public ResourceNotFoundException(String resourceName, String fieldName, String fieldValue) {
9
+ super(String.format("%s not found with %s : '%s'", resourceName, fieldName, fieldValue));
10
+ }
11
+
12
+ public ResourceNotFoundException(String message) {
13
+ super(message);
14
+ }
15
+ }
src/main/java/com/dalab/policyengine/config/OpenAPIConfiguration.java ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.config;
2
+
3
+ import org.springframework.beans.factory.annotation.Value;
4
+ import org.springframework.context.annotation.Bean;
5
+ import org.springframework.context.annotation.Configuration;
6
+
7
+ import io.swagger.v3.oas.models.OpenAPI;
8
+ import io.swagger.v3.oas.models.info.Info;
9
+ import io.swagger.v3.oas.models.info.License;
10
+
11
+ @Configuration
12
+ public class OpenAPIConfiguration {
13
+
14
+ @Bean
15
+ public OpenAPI customOpenAPI(
16
+ @Value("${spring.application.name}") String appName,
17
+ @Value("${spring.application.description:DALab Policy Engine Microservice}") String appDescription,
18
+ @Value("${spring.application.version:v0.0.1}") String appVersion) {
19
+ return new OpenAPI()
20
+ .info(new Info()
21
+ .title(appName)
22
+ .version(appVersion)
23
+ .description(appDescription)
24
+ .termsOfService("http://swagger.io/terms/") // Replace with actual terms
25
+ .license(new License().name("Apache 2.0").url("http://springdoc.org"))); // Replace with actual license
26
+ }
27
+ }
src/main/java/com/dalab/policyengine/config/SecurityConfiguration.java ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.config;
2
+
3
+ import org.springframework.beans.factory.annotation.Value;
4
+ import org.springframework.context.annotation.Bean;
5
+ import org.springframework.context.annotation.Configuration;
6
+ import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
7
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
8
+ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
9
+ import org.springframework.security.config.http.SessionCreationPolicy;
10
+ import org.springframework.security.oauth2.jwt.JwtDecoder;
11
+ import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
12
+ import org.springframework.security.web.SecurityFilterChain;
13
+
14
+ @Configuration
15
+ @EnableWebSecurity
16
+ @EnableMethodSecurity(prePostEnabled = true, securedEnabled = true)
17
+ public class SecurityConfiguration {
18
+
19
+ @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
20
+ private String issuerUri;
21
+
22
+ @Bean
23
+ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
24
+ http
25
+ .csrf(csrf -> csrf.disable()) // Typically disable CSRF for stateless REST APIs
26
+ .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
27
+ .authorizeHttpRequests(authz -> authz
28
+ // Define public endpoints if any (e.g., actuator/health, swagger-ui)
29
+ // .requestMatchers("/public/**").permitAll()
30
+ .anyRequest().authenticated() // All other requests require authentication
31
+ )
32
+ .oauth2ResourceServer(oauth2 -> oauth2
33
+ .jwt(jwt -> jwt.decoder(jwtDecoder()))
34
+ );
35
+ return http.build();
36
+ }
37
+
38
+ @Bean
39
+ public JwtDecoder jwtDecoder() {
40
+ // NimbusJwtDecoder automatically fetches the JWK Set URI from the issuer URI
41
+ // (e.g., ISSUER_URI/.well-known/openid-configuration or ISSUER_URI/protocol/openid-connect/certs)
42
+ return NimbusJwtDecoder.withIssuerLocation(issuerUri).build();
43
+ }
44
+ }
src/main/java/com/dalab/policyengine/dto/EventAnalyticsDTO.java ADDED
@@ -0,0 +1,349 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.dto;
2
+
3
+ import java.time.Instant;
4
+ import java.util.List;
5
+ import java.util.Map;
6
+
7
+ import com.dalab.policyengine.model.EventSeverity;
8
+ import com.dalab.policyengine.model.EventType;
9
+
10
+ /**
11
+ * DTO for Event Center analytics and metrics dashboard.
12
+ */
13
+ public class EventAnalyticsDTO {
14
+
15
+ // Summary metrics
16
+ private Long totalEventsToday;
17
+ private Long totalEventsThisWeek;
18
+ private Long totalEventsThisMonth;
19
+ private Long totalActiveSubscriptions;
20
+ private Long totalUsersWithSubscriptions;
21
+
22
+ // Event distribution by type
23
+ private List<EventTypeCount> eventsByType;
24
+
25
+ // Event distribution by severity
26
+ private List<EventSeverityCount> eventsBySeverity;
27
+
28
+ // Event distribution by source service
29
+ private List<SourceServiceCount> eventsBySourceService;
30
+
31
+ // Top active subscriptions
32
+ private List<TopSubscription> topActiveSubscriptions;
33
+
34
+ // Recent event trends (hourly for last 24 hours)
35
+ private List<EventTrendPoint> recentTrends;
36
+
37
+ // Response time metrics
38
+ private ResponseTimeMetrics responseMetrics;
39
+
40
+ // Alert statistics
41
+ private AlertStatistics alertStats;
42
+
43
+ // Time range for this analytics report
44
+ private Instant fromTime;
45
+ private Instant toTime;
46
+ private Instant generatedAt;
47
+
48
+ // Constructors
49
+ public EventAnalyticsDTO() {
50
+ this.generatedAt = Instant.now();
51
+ }
52
+
53
+ public EventAnalyticsDTO(Instant fromTime, Instant toTime) {
54
+ this.fromTime = fromTime;
55
+ this.toTime = toTime;
56
+ this.generatedAt = Instant.now();
57
+ }
58
+
59
+ // Getters and Setters
60
+
61
+ public Long getTotalEventsToday() {
62
+ return totalEventsToday;
63
+ }
64
+
65
+ public void setTotalEventsToday(Long totalEventsToday) {
66
+ this.totalEventsToday = totalEventsToday;
67
+ }
68
+
69
+ public Long getTotalEventsThisWeek() {
70
+ return totalEventsThisWeek;
71
+ }
72
+
73
+ public void setTotalEventsThisWeek(Long totalEventsThisWeek) {
74
+ this.totalEventsThisWeek = totalEventsThisWeek;
75
+ }
76
+
77
+ public Long getTotalEventsThisMonth() {
78
+ return totalEventsThisMonth;
79
+ }
80
+
81
+ public void setTotalEventsThisMonth(Long totalEventsThisMonth) {
82
+ this.totalEventsThisMonth = totalEventsThisMonth;
83
+ }
84
+
85
+ public Long getTotalActiveSubscriptions() {
86
+ return totalActiveSubscriptions;
87
+ }
88
+
89
+ public void setTotalActiveSubscriptions(Long totalActiveSubscriptions) {
90
+ this.totalActiveSubscriptions = totalActiveSubscriptions;
91
+ }
92
+
93
+ public Long getTotalUsersWithSubscriptions() {
94
+ return totalUsersWithSubscriptions;
95
+ }
96
+
97
+ public void setTotalUsersWithSubscriptions(Long totalUsersWithSubscriptions) {
98
+ this.totalUsersWithSubscriptions = totalUsersWithSubscriptions;
99
+ }
100
+
101
+ public List<EventTypeCount> getEventsByType() {
102
+ return eventsByType;
103
+ }
104
+
105
+ public void setEventsByType(List<EventTypeCount> eventsByType) {
106
+ this.eventsByType = eventsByType;
107
+ }
108
+
109
+ public List<EventSeverityCount> getEventsBySeverity() {
110
+ return eventsBySeverity;
111
+ }
112
+
113
+ public void setEventsBySeverity(List<EventSeverityCount> eventsBySeverity) {
114
+ this.eventsBySeverity = eventsBySeverity;
115
+ }
116
+
117
+ public List<SourceServiceCount> getEventsBySourceService() {
118
+ return eventsBySourceService;
119
+ }
120
+
121
+ public void setEventsBySourceService(List<SourceServiceCount> eventsBySourceService) {
122
+ this.eventsBySourceService = eventsBySourceService;
123
+ }
124
+
125
+ public List<TopSubscription> getTopActiveSubscriptions() {
126
+ return topActiveSubscriptions;
127
+ }
128
+
129
+ public void setTopActiveSubscriptions(List<TopSubscription> topActiveSubscriptions) {
130
+ this.topActiveSubscriptions = topActiveSubscriptions;
131
+ }
132
+
133
+ public List<EventTrendPoint> getRecentTrends() {
134
+ return recentTrends;
135
+ }
136
+
137
+ public void setRecentTrends(List<EventTrendPoint> recentTrends) {
138
+ this.recentTrends = recentTrends;
139
+ }
140
+
141
+ public ResponseTimeMetrics getResponseMetrics() {
142
+ return responseMetrics;
143
+ }
144
+
145
+ public void setResponseMetrics(ResponseTimeMetrics responseMetrics) {
146
+ this.responseMetrics = responseMetrics;
147
+ }
148
+
149
+ public AlertStatistics getAlertStats() {
150
+ return alertStats;
151
+ }
152
+
153
+ public void setAlertStats(AlertStatistics alertStats) {
154
+ this.alertStats = alertStats;
155
+ }
156
+
157
+ public Instant getFromTime() {
158
+ return fromTime;
159
+ }
160
+
161
+ public void setFromTime(Instant fromTime) {
162
+ this.fromTime = fromTime;
163
+ }
164
+
165
+ public Instant getToTime() {
166
+ return toTime;
167
+ }
168
+
169
+ public void setToTime(Instant toTime) {
170
+ this.toTime = toTime;
171
+ }
172
+
173
+ public Instant getGeneratedAt() {
174
+ return generatedAt;
175
+ }
176
+
177
+ public void setGeneratedAt(Instant generatedAt) {
178
+ this.generatedAt = generatedAt;
179
+ }
180
+
181
+ @Override
182
+ public String toString() {
183
+ return "EventAnalyticsDTO{" +
184
+ "totalEventsToday=" + totalEventsToday +
185
+ ", totalEventsThisWeek=" + totalEventsThisWeek +
186
+ ", totalEventsThisMonth=" + totalEventsThisMonth +
187
+ ", totalActiveSubscriptions=" + totalActiveSubscriptions +
188
+ ", fromTime=" + fromTime +
189
+ ", toTime=" + toTime +
190
+ ", generatedAt=" + generatedAt +
191
+ '}';
192
+ }
193
+
194
+ // Nested classes for analytics data structures
195
+
196
+ public static class EventTypeCount {
197
+ private EventType eventType;
198
+ private Long count;
199
+ private Double percentage;
200
+
201
+ public EventTypeCount() {}
202
+
203
+ public EventTypeCount(EventType eventType, Long count) {
204
+ this.eventType = eventType;
205
+ this.count = count;
206
+ }
207
+
208
+ public EventType getEventType() { return eventType; }
209
+ public void setEventType(EventType eventType) { this.eventType = eventType; }
210
+ public Long getCount() { return count; }
211
+ public void setCount(Long count) { this.count = count; }
212
+ public Double getPercentage() { return percentage; }
213
+ public void setPercentage(Double percentage) { this.percentage = percentage; }
214
+ }
215
+
216
+ public static class EventSeverityCount {
217
+ private EventSeverity severity;
218
+ private Long count;
219
+ private Double percentage;
220
+
221
+ public EventSeverityCount() {}
222
+
223
+ public EventSeverityCount(EventSeverity severity, Long count) {
224
+ this.severity = severity;
225
+ this.count = count;
226
+ }
227
+
228
+ public EventSeverity getSeverity() { return severity; }
229
+ public void setSeverity(EventSeverity severity) { this.severity = severity; }
230
+ public Long getCount() { return count; }
231
+ public void setCount(Long count) { this.count = count; }
232
+ public Double getPercentage() { return percentage; }
233
+ public void setPercentage(Double percentage) { this.percentage = percentage; }
234
+ }
235
+
236
+ public static class SourceServiceCount {
237
+ private String sourceService;
238
+ private Long count;
239
+ private Double percentage;
240
+
241
+ public SourceServiceCount() {}
242
+
243
+ public SourceServiceCount(String sourceService, Long count) {
244
+ this.sourceService = sourceService;
245
+ this.count = count;
246
+ }
247
+
248
+ public String getSourceService() { return sourceService; }
249
+ public void setSourceService(String sourceService) { this.sourceService = sourceService; }
250
+ public Long getCount() { return count; }
251
+ public void setCount(Long count) { this.count = count; }
252
+ public Double getPercentage() { return percentage; }
253
+ public void setPercentage(Double percentage) { this.percentage = percentage; }
254
+ }
255
+
256
+ public static class TopSubscription {
257
+ private String subscriptionName;
258
+ private Long eventsMatched;
259
+ private Long notificationsSent;
260
+ private String ownerName;
261
+ private Instant lastActivity;
262
+
263
+ public TopSubscription() {}
264
+
265
+ public TopSubscription(String subscriptionName, Long eventsMatched) {
266
+ this.subscriptionName = subscriptionName;
267
+ this.eventsMatched = eventsMatched;
268
+ }
269
+
270
+ public String getSubscriptionName() { return subscriptionName; }
271
+ public void setSubscriptionName(String subscriptionName) { this.subscriptionName = subscriptionName; }
272
+ public Long getEventsMatched() { return eventsMatched; }
273
+ public void setEventsMatched(Long eventsMatched) { this.eventsMatched = eventsMatched; }
274
+ public Long getNotificationsSent() { return notificationsSent; }
275
+ public void setNotificationsSent(Long notificationsSent) { this.notificationsSent = notificationsSent; }
276
+ public String getOwnerName() { return ownerName; }
277
+ public void setOwnerName(String ownerName) { this.ownerName = ownerName; }
278
+ public Instant getLastActivity() { return lastActivity; }
279
+ public void setLastActivity(Instant lastActivity) { this.lastActivity = lastActivity; }
280
+ }
281
+
282
+ public static class EventTrendPoint {
283
+ private Instant timestamp;
284
+ private Long eventCount;
285
+ private Long criticalCount;
286
+ private Long highCount;
287
+ private Long mediumCount;
288
+ private Long lowCount;
289
+
290
+ public EventTrendPoint() {}
291
+
292
+ public EventTrendPoint(Instant timestamp, Long eventCount) {
293
+ this.timestamp = timestamp;
294
+ this.eventCount = eventCount;
295
+ }
296
+
297
+ public Instant getTimestamp() { return timestamp; }
298
+ public void setTimestamp(Instant timestamp) { this.timestamp = timestamp; }
299
+ public Long getEventCount() { return eventCount; }
300
+ public void setEventCount(Long eventCount) { this.eventCount = eventCount; }
301
+ public Long getCriticalCount() { return criticalCount; }
302
+ public void setCriticalCount(Long criticalCount) { this.criticalCount = criticalCount; }
303
+ public Long getHighCount() { return highCount; }
304
+ public void setHighCount(Long highCount) { this.highCount = highCount; }
305
+ public Long getMediumCount() { return mediumCount; }
306
+ public void setMediumCount(Long mediumCount) { this.mediumCount = mediumCount; }
307
+ public Long getLowCount() { return lowCount; }
308
+ public void setLowCount(Long lowCount) { this.lowCount = lowCount; }
309
+ }
310
+
311
+ public static class ResponseTimeMetrics {
312
+ private Double averageProcessingTimeMs;
313
+ private Double averageNotificationTimeMs;
314
+ private Long totalProcessedEvents;
315
+ private Long failedNotifications;
316
+ private Double successRate;
317
+
318
+ public ResponseTimeMetrics() {}
319
+
320
+ public Double getAverageProcessingTimeMs() { return averageProcessingTimeMs; }
321
+ public void setAverageProcessingTimeMs(Double averageProcessingTimeMs) { this.averageProcessingTimeMs = averageProcessingTimeMs; }
322
+ public Double getAverageNotificationTimeMs() { return averageNotificationTimeMs; }
323
+ public void setAverageNotificationTimeMs(Double averageNotificationTimeMs) { this.averageNotificationTimeMs = averageNotificationTimeMs; }
324
+ public Long getTotalProcessedEvents() { return totalProcessedEvents; }
325
+ public void setTotalProcessedEvents(Long totalProcessedEvents) { this.totalProcessedEvents = totalProcessedEvents; }
326
+ public Long getFailedNotifications() { return failedNotifications; }
327
+ public void setFailedNotifications(Long failedNotifications) { this.failedNotifications = failedNotifications; }
328
+ public Double getSuccessRate() { return successRate; }
329
+ public void setSuccessRate(Double successRate) { this.successRate = successRate; }
330
+ }
331
+
332
+ public static class AlertStatistics {
333
+ private Long totalAlertsTriggered;
334
+ private Long totalNotificationsSent;
335
+ private Long totalActionsExecuted;
336
+ private Map<String, Long> alertsByChannel; // email, slack, webhook, etc.
337
+
338
+ public AlertStatistics() {}
339
+
340
+ public Long getTotalAlertsTriggered() { return totalAlertsTriggered; }
341
+ public void setTotalAlertsTriggered(Long totalAlertsTriggered) { this.totalAlertsTriggered = totalAlertsTriggered; }
342
+ public Long getTotalNotificationsSent() { return totalNotificationsSent; }
343
+ public void setTotalNotificationsSent(Long totalNotificationsSent) { this.totalNotificationsSent = totalNotificationsSent; }
344
+ public Long getTotalActionsExecuted() { return totalActionsExecuted; }
345
+ public void setTotalActionsExecuted(Long totalActionsExecuted) { this.totalActionsExecuted = totalActionsExecuted; }
346
+ public Map<String, Long> getAlertsByChannel() { return alertsByChannel; }
347
+ public void setAlertsByChannel(Map<String, Long> alertsByChannel) { this.alertsByChannel = alertsByChannel; }
348
+ }
349
+ }
src/main/java/com/dalab/policyengine/dto/EventStreamDTO.java ADDED
@@ -0,0 +1,216 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.dto;
2
+
3
+ import java.time.Instant;
4
+ import java.util.Map;
5
+ import java.util.UUID;
6
+
7
+ import com.dalab.policyengine.model.EventSeverity;
8
+ import com.dalab.policyengine.model.EventType;
9
+
10
+ /**
11
+ * DTO for streaming events in real-time to the Event Center UI.
12
+ */
13
+ public class EventStreamDTO {
14
+
15
+ private UUID eventId;
16
+ private EventType eventType;
17
+ private EventSeverity severity;
18
+ private String sourceService;
19
+ private String title;
20
+ private String description;
21
+ private UUID assetId;
22
+ private String assetName;
23
+ private UUID policyId;
24
+ private String policyName;
25
+ private Map<String, Object> eventData;
26
+ private Map<String, Object> metadata;
27
+ private Instant timestamp;
28
+ private UUID userId;
29
+ private String userAction;
30
+
31
+ // Event processing information
32
+ private Boolean isProcessed;
33
+ private Integer matchingSubscriptionsCount;
34
+ private Boolean notificationSent;
35
+ private Boolean actionTriggered;
36
+
37
+ // Constructors
38
+ public EventStreamDTO() {}
39
+
40
+ public EventStreamDTO(UUID eventId, EventType eventType, EventSeverity severity, String sourceService) {
41
+ this.eventId = eventId;
42
+ this.eventType = eventType;
43
+ this.severity = severity;
44
+ this.sourceService = sourceService;
45
+ this.timestamp = Instant.now();
46
+ }
47
+
48
+ // Getters and Setters
49
+
50
+ public UUID getEventId() {
51
+ return eventId;
52
+ }
53
+
54
+ public void setEventId(UUID eventId) {
55
+ this.eventId = eventId;
56
+ }
57
+
58
+ public EventType getEventType() {
59
+ return eventType;
60
+ }
61
+
62
+ public void setEventType(EventType eventType) {
63
+ this.eventType = eventType;
64
+ }
65
+
66
+ public EventSeverity getSeverity() {
67
+ return severity;
68
+ }
69
+
70
+ public void setSeverity(EventSeverity severity) {
71
+ this.severity = severity;
72
+ }
73
+
74
+ public String getSourceService() {
75
+ return sourceService;
76
+ }
77
+
78
+ public void setSourceService(String sourceService) {
79
+ this.sourceService = sourceService;
80
+ }
81
+
82
+ public String getTitle() {
83
+ return title;
84
+ }
85
+
86
+ public void setTitle(String title) {
87
+ this.title = title;
88
+ }
89
+
90
+ public String getDescription() {
91
+ return description;
92
+ }
93
+
94
+ public void setDescription(String description) {
95
+ this.description = description;
96
+ }
97
+
98
+ public UUID getAssetId() {
99
+ return assetId;
100
+ }
101
+
102
+ public void setAssetId(UUID assetId) {
103
+ this.assetId = assetId;
104
+ }
105
+
106
+ public String getAssetName() {
107
+ return assetName;
108
+ }
109
+
110
+ public void setAssetName(String assetName) {
111
+ this.assetName = assetName;
112
+ }
113
+
114
+ public UUID getPolicyId() {
115
+ return policyId;
116
+ }
117
+
118
+ public void setPolicyId(UUID policyId) {
119
+ this.policyId = policyId;
120
+ }
121
+
122
+ public String getPolicyName() {
123
+ return policyName;
124
+ }
125
+
126
+ public void setPolicyName(String policyName) {
127
+ this.policyName = policyName;
128
+ }
129
+
130
+ public Map<String, Object> getEventData() {
131
+ return eventData;
132
+ }
133
+
134
+ public void setEventData(Map<String, Object> eventData) {
135
+ this.eventData = eventData;
136
+ }
137
+
138
+ public Map<String, Object> getMetadata() {
139
+ return metadata;
140
+ }
141
+
142
+ public void setMetadata(Map<String, Object> metadata) {
143
+ this.metadata = metadata;
144
+ }
145
+
146
+ public Instant getTimestamp() {
147
+ return timestamp;
148
+ }
149
+
150
+ public void setTimestamp(Instant timestamp) {
151
+ this.timestamp = timestamp;
152
+ }
153
+
154
+ public UUID getUserId() {
155
+ return userId;
156
+ }
157
+
158
+ public void setUserId(UUID userId) {
159
+ this.userId = userId;
160
+ }
161
+
162
+ public String getUserAction() {
163
+ return userAction;
164
+ }
165
+
166
+ public void setUserAction(String userAction) {
167
+ this.userAction = userAction;
168
+ }
169
+
170
+ public Boolean getIsProcessed() {
171
+ return isProcessed;
172
+ }
173
+
174
+ public void setIsProcessed(Boolean isProcessed) {
175
+ this.isProcessed = isProcessed;
176
+ }
177
+
178
+ public Integer getMatchingSubscriptionsCount() {
179
+ return matchingSubscriptionsCount;
180
+ }
181
+
182
+ public void setMatchingSubscriptionsCount(Integer matchingSubscriptionsCount) {
183
+ this.matchingSubscriptionsCount = matchingSubscriptionsCount;
184
+ }
185
+
186
+ public Boolean getNotificationSent() {
187
+ return notificationSent;
188
+ }
189
+
190
+ public void setNotificationSent(Boolean notificationSent) {
191
+ this.notificationSent = notificationSent;
192
+ }
193
+
194
+ public Boolean getActionTriggered() {
195
+ return actionTriggered;
196
+ }
197
+
198
+ public void setActionTriggered(Boolean actionTriggered) {
199
+ this.actionTriggered = actionTriggered;
200
+ }
201
+
202
+ @Override
203
+ public String toString() {
204
+ return "EventStreamDTO{" +
205
+ "eventId=" + eventId +
206
+ ", eventType=" + eventType +
207
+ ", severity=" + severity +
208
+ ", sourceService='" + sourceService + '\'' +
209
+ ", title='" + title + '\'' +
210
+ ", assetId=" + assetId +
211
+ ", policyId=" + policyId +
212
+ ", timestamp=" + timestamp +
213
+ ", isProcessed=" + isProcessed +
214
+ '}';
215
+ }
216
+ }
src/main/java/com/dalab/policyengine/dto/EventSubscriptionInputDTO.java ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.dto;
2
+
3
+ import java.util.List;
4
+ import java.util.Map;
5
+
6
+ import jakarta.validation.constraints.NotBlank;
7
+ import jakarta.validation.constraints.Size;
8
+
9
+ import com.dalab.policyengine.model.EventSeverity;
10
+ import com.dalab.policyengine.model.EventType;
11
+
12
+ /**
13
+ * DTO for creating or updating event subscriptions.
14
+ */
15
+ public class EventSubscriptionInputDTO {
16
+
17
+ @NotBlank(message = "Subscription name is required")
18
+ @Size(max = 255, message = "Subscription name must not exceed 255 characters")
19
+ private String name;
20
+
21
+ @Size(max = 1000, message = "Description must not exceed 1000 characters")
22
+ private String description;
23
+
24
+ /**
25
+ * Event types to subscribe to
26
+ */
27
+ private List<EventType> eventTypes;
28
+
29
+ /**
30
+ * Event severity levels to include
31
+ */
32
+ private List<EventSeverity> severities;
33
+
34
+ /**
35
+ * Source services to monitor
36
+ */
37
+ private List<String> sourceServices;
38
+
39
+ /**
40
+ * Event filtering rules
41
+ */
42
+ private List<EventRuleInputDTO> rules;
43
+
44
+ /**
45
+ * Notification configuration
46
+ * Example: { "email": true, "slack": { "channel": "#alerts", "webhook": "https://..." } }
47
+ */
48
+ private Map<String, Object> notificationConfig;
49
+
50
+ /**
51
+ * Action configuration for automated responses
52
+ * Example: { "autoQuarantine": true, "escalateTo": "admin", "maxRetries": 3 }
53
+ */
54
+ private Map<String, Object> actionConfig;
55
+
56
+ // Constructors
57
+ public EventSubscriptionInputDTO() {}
58
+
59
+ public EventSubscriptionInputDTO(String name) {
60
+ this.name = name;
61
+ }
62
+
63
+ // Getters and Setters
64
+
65
+ public String getName() {
66
+ return name;
67
+ }
68
+
69
+ public void setName(String name) {
70
+ this.name = name;
71
+ }
72
+
73
+ public String getDescription() {
74
+ return description;
75
+ }
76
+
77
+ public void setDescription(String description) {
78
+ this.description = description;
79
+ }
80
+
81
+ public List<EventType> getEventTypes() {
82
+ return eventTypes;
83
+ }
84
+
85
+ public void setEventTypes(List<EventType> eventTypes) {
86
+ this.eventTypes = eventTypes;
87
+ }
88
+
89
+ public List<EventSeverity> getSeverities() {
90
+ return severities;
91
+ }
92
+
93
+ public void setSeverities(List<EventSeverity> severities) {
94
+ this.severities = severities;
95
+ }
96
+
97
+ public List<String> getSourceServices() {
98
+ return sourceServices;
99
+ }
100
+
101
+ public void setSourceServices(List<String> sourceServices) {
102
+ this.sourceServices = sourceServices;
103
+ }
104
+
105
+ public List<EventRuleInputDTO> getRules() {
106
+ return rules;
107
+ }
108
+
109
+ public void setRules(List<EventRuleInputDTO> rules) {
110
+ this.rules = rules;
111
+ }
112
+
113
+ public Map<String, Object> getNotificationConfig() {
114
+ return notificationConfig;
115
+ }
116
+
117
+ public void setNotificationConfig(Map<String, Object> notificationConfig) {
118
+ this.notificationConfig = notificationConfig;
119
+ }
120
+
121
+ public Map<String, Object> getActionConfig() {
122
+ return actionConfig;
123
+ }
124
+
125
+ public void setActionConfig(Map<String, Object> actionConfig) {
126
+ this.actionConfig = actionConfig;
127
+ }
128
+
129
+ @Override
130
+ public String toString() {
131
+ return "EventSubscriptionInputDTO{" +
132
+ "name='" + name + '\'' +
133
+ ", description='" + description + '\'' +
134
+ ", eventTypes=" + eventTypes +
135
+ ", severities=" + severities +
136
+ ", sourceServices=" + sourceServices +
137
+ ", rulesCount=" + (rules != null ? rules.size() : 0) +
138
+ '}';
139
+ }
140
+
141
+ /**
142
+ * Nested DTO for event rules within subscription input
143
+ */
144
+ public static class EventRuleInputDTO {
145
+ @NotBlank(message = "Rule name is required")
146
+ @Size(max = 255, message = "Rule name must not exceed 255 characters")
147
+ private String name;
148
+
149
+ @Size(max = 500, message = "Rule description must not exceed 500 characters")
150
+ private String description;
151
+
152
+ @NotBlank(message = "Rule condition is required")
153
+ private String condition;
154
+
155
+ private Integer priority = 1;
156
+
157
+ private Boolean enabled = true;
158
+
159
+ private Map<String, Object> parameters;
160
+
161
+ // Constructors
162
+ public EventRuleInputDTO() {}
163
+
164
+ public EventRuleInputDTO(String name, String condition) {
165
+ this.name = name;
166
+ this.condition = condition;
167
+ }
168
+
169
+ // Getters and Setters
170
+
171
+ public String getName() {
172
+ return name;
173
+ }
174
+
175
+ public void setName(String name) {
176
+ this.name = name;
177
+ }
178
+
179
+ public String getDescription() {
180
+ return description;
181
+ }
182
+
183
+ public void setDescription(String description) {
184
+ this.description = description;
185
+ }
186
+
187
+ public String getCondition() {
188
+ return condition;
189
+ }
190
+
191
+ public void setCondition(String condition) {
192
+ this.condition = condition;
193
+ }
194
+
195
+ public Integer getPriority() {
196
+ return priority;
197
+ }
198
+
199
+ public void setPriority(Integer priority) {
200
+ this.priority = priority;
201
+ }
202
+
203
+ public Boolean getEnabled() {
204
+ return enabled;
205
+ }
206
+
207
+ public void setEnabled(Boolean enabled) {
208
+ this.enabled = enabled;
209
+ }
210
+
211
+ public Map<String, Object> getParameters() {
212
+ return parameters;
213
+ }
214
+
215
+ public void setParameters(Map<String, Object> parameters) {
216
+ this.parameters = parameters;
217
+ }
218
+
219
+ @Override
220
+ public String toString() {
221
+ return "EventRuleInputDTO{" +
222
+ "name='" + name + '\'' +
223
+ ", condition='" + condition + '\'' +
224
+ ", priority=" + priority +
225
+ ", enabled=" + enabled +
226
+ '}';
227
+ }
228
+ }
229
+ }
src/main/java/com/dalab/policyengine/dto/EventSubscriptionOutputDTO.java ADDED
@@ -0,0 +1,343 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.dto;
2
+
3
+ import java.time.Instant;
4
+ import java.util.List;
5
+ import java.util.Map;
6
+ import java.util.UUID;
7
+
8
+ import com.dalab.policyengine.model.EventSeverity;
9
+ import com.dalab.policyengine.model.EventSubscriptionStatus;
10
+ import com.dalab.policyengine.model.EventType;
11
+
12
+ /**
13
+ * DTO for returning event subscription information.
14
+ */
15
+ public class EventSubscriptionOutputDTO {
16
+
17
+ private UUID id;
18
+ private String name;
19
+ private String description;
20
+ private UUID userId;
21
+ private EventSubscriptionStatus status;
22
+ private List<EventType> eventTypes;
23
+ private List<EventSeverity> severities;
24
+ private List<String> sourceServices;
25
+ private List<EventRuleOutputDTO> rules;
26
+ private Map<String, Object> notificationConfig;
27
+ private Map<String, Object> actionConfig;
28
+ private Instant createdAt;
29
+ private Instant updatedAt;
30
+ private UUID createdByUserId;
31
+ private UUID updatedByUserId;
32
+
33
+ // Statistics
34
+ private Long totalRulesCount;
35
+ private Long enabledRulesCount;
36
+ private Long eventsMatchedCount;
37
+ private Instant lastEventMatchedAt;
38
+
39
+ // Constructors
40
+ public EventSubscriptionOutputDTO() {}
41
+
42
+ public EventSubscriptionOutputDTO(UUID id, String name, UUID userId, EventSubscriptionStatus status) {
43
+ this.id = id;
44
+ this.name = name;
45
+ this.userId = userId;
46
+ this.status = status;
47
+ }
48
+
49
+ // Getters and Setters
50
+
51
+ public UUID getId() {
52
+ return id;
53
+ }
54
+
55
+ public void setId(UUID id) {
56
+ this.id = id;
57
+ }
58
+
59
+ public String getName() {
60
+ return name;
61
+ }
62
+
63
+ public void setName(String name) {
64
+ this.name = name;
65
+ }
66
+
67
+ public String getDescription() {
68
+ return description;
69
+ }
70
+
71
+ public void setDescription(String description) {
72
+ this.description = description;
73
+ }
74
+
75
+ public UUID getUserId() {
76
+ return userId;
77
+ }
78
+
79
+ public void setUserId(UUID userId) {
80
+ this.userId = userId;
81
+ }
82
+
83
+ public EventSubscriptionStatus getStatus() {
84
+ return status;
85
+ }
86
+
87
+ public void setStatus(EventSubscriptionStatus status) {
88
+ this.status = status;
89
+ }
90
+
91
+ public List<EventType> getEventTypes() {
92
+ return eventTypes;
93
+ }
94
+
95
+ public void setEventTypes(List<EventType> eventTypes) {
96
+ this.eventTypes = eventTypes;
97
+ }
98
+
99
+ public List<EventSeverity> getSeverities() {
100
+ return severities;
101
+ }
102
+
103
+ public void setSeverities(List<EventSeverity> severities) {
104
+ this.severities = severities;
105
+ }
106
+
107
+ public List<String> getSourceServices() {
108
+ return sourceServices;
109
+ }
110
+
111
+ public void setSourceServices(List<String> sourceServices) {
112
+ this.sourceServices = sourceServices;
113
+ }
114
+
115
+ public List<EventRuleOutputDTO> getRules() {
116
+ return rules;
117
+ }
118
+
119
+ public void setRules(List<EventRuleOutputDTO> rules) {
120
+ this.rules = rules;
121
+ }
122
+
123
+ public Map<String, Object> getNotificationConfig() {
124
+ return notificationConfig;
125
+ }
126
+
127
+ public void setNotificationConfig(Map<String, Object> notificationConfig) {
128
+ this.notificationConfig = notificationConfig;
129
+ }
130
+
131
+ public Map<String, Object> getActionConfig() {
132
+ return actionConfig;
133
+ }
134
+
135
+ public void setActionConfig(Map<String, Object> actionConfig) {
136
+ this.actionConfig = actionConfig;
137
+ }
138
+
139
+ public Instant getCreatedAt() {
140
+ return createdAt;
141
+ }
142
+
143
+ public void setCreatedAt(Instant createdAt) {
144
+ this.createdAt = createdAt;
145
+ }
146
+
147
+ public Instant getUpdatedAt() {
148
+ return updatedAt;
149
+ }
150
+
151
+ public void setUpdatedAt(Instant updatedAt) {
152
+ this.updatedAt = updatedAt;
153
+ }
154
+
155
+ public UUID getCreatedByUserId() {
156
+ return createdByUserId;
157
+ }
158
+
159
+ public void setCreatedByUserId(UUID createdByUserId) {
160
+ this.createdByUserId = createdByUserId;
161
+ }
162
+
163
+ public UUID getUpdatedByUserId() {
164
+ return updatedByUserId;
165
+ }
166
+
167
+ public void setUpdatedByUserId(UUID updatedByUserId) {
168
+ this.updatedByUserId = updatedByUserId;
169
+ }
170
+
171
+ public Long getTotalRulesCount() {
172
+ return totalRulesCount;
173
+ }
174
+
175
+ public void setTotalRulesCount(Long totalRulesCount) {
176
+ this.totalRulesCount = totalRulesCount;
177
+ }
178
+
179
+ public Long getEnabledRulesCount() {
180
+ return enabledRulesCount;
181
+ }
182
+
183
+ public void setEnabledRulesCount(Long enabledRulesCount) {
184
+ this.enabledRulesCount = enabledRulesCount;
185
+ }
186
+
187
+ public Long getEventsMatchedCount() {
188
+ return eventsMatchedCount;
189
+ }
190
+
191
+ public void setEventsMatchedCount(Long eventsMatchedCount) {
192
+ this.eventsMatchedCount = eventsMatchedCount;
193
+ }
194
+
195
+ public Instant getLastEventMatchedAt() {
196
+ return lastEventMatchedAt;
197
+ }
198
+
199
+ public void setLastEventMatchedAt(Instant lastEventMatchedAt) {
200
+ this.lastEventMatchedAt = lastEventMatchedAt;
201
+ }
202
+
203
+ @Override
204
+ public String toString() {
205
+ return "EventSubscriptionOutputDTO{" +
206
+ "id=" + id +
207
+ ", name='" + name + '\'' +
208
+ ", userId=" + userId +
209
+ ", status=" + status +
210
+ ", eventTypes=" + eventTypes +
211
+ ", severities=" + severities +
212
+ ", rulesCount=" + totalRulesCount +
213
+ ", eventsMatchedCount=" + eventsMatchedCount +
214
+ '}';
215
+ }
216
+
217
+ /**
218
+ * Nested DTO for event rules within subscription output
219
+ */
220
+ public static class EventRuleOutputDTO {
221
+ private UUID id;
222
+ private String name;
223
+ private String description;
224
+ private String condition;
225
+ private Integer priority;
226
+ private Boolean enabled;
227
+ private Map<String, Object> parameters;
228
+ private Instant createdAt;
229
+ private Instant updatedAt;
230
+ private UUID createdByUserId;
231
+ private UUID updatedByUserId;
232
+
233
+ // Constructors
234
+ public EventRuleOutputDTO() {}
235
+
236
+ public EventRuleOutputDTO(UUID id, String name, String condition) {
237
+ this.id = id;
238
+ this.name = name;
239
+ this.condition = condition;
240
+ }
241
+
242
+ // Getters and Setters
243
+
244
+ public UUID getId() {
245
+ return id;
246
+ }
247
+
248
+ public void setId(UUID id) {
249
+ this.id = id;
250
+ }
251
+
252
+ public String getName() {
253
+ return name;
254
+ }
255
+
256
+ public void setName(String name) {
257
+ this.name = name;
258
+ }
259
+
260
+ public String getDescription() {
261
+ return description;
262
+ }
263
+
264
+ public void setDescription(String description) {
265
+ this.description = description;
266
+ }
267
+
268
+ public String getCondition() {
269
+ return condition;
270
+ }
271
+
272
+ public void setCondition(String condition) {
273
+ this.condition = condition;
274
+ }
275
+
276
+ public Integer getPriority() {
277
+ return priority;
278
+ }
279
+
280
+ public void setPriority(Integer priority) {
281
+ this.priority = priority;
282
+ }
283
+
284
+ public Boolean getEnabled() {
285
+ return enabled;
286
+ }
287
+
288
+ public void setEnabled(Boolean enabled) {
289
+ this.enabled = enabled;
290
+ }
291
+
292
+ public Map<String, Object> getParameters() {
293
+ return parameters;
294
+ }
295
+
296
+ public void setParameters(Map<String, Object> parameters) {
297
+ this.parameters = parameters;
298
+ }
299
+
300
+ public Instant getCreatedAt() {
301
+ return createdAt;
302
+ }
303
+
304
+ public void setCreatedAt(Instant createdAt) {
305
+ this.createdAt = createdAt;
306
+ }
307
+
308
+ public Instant getUpdatedAt() {
309
+ return updatedAt;
310
+ }
311
+
312
+ public void setUpdatedAt(Instant updatedAt) {
313
+ this.updatedAt = updatedAt;
314
+ }
315
+
316
+ public UUID getCreatedByUserId() {
317
+ return createdByUserId;
318
+ }
319
+
320
+ public void setCreatedByUserId(UUID createdByUserId) {
321
+ this.createdByUserId = createdByUserId;
322
+ }
323
+
324
+ public UUID getUpdatedByUserId() {
325
+ return updatedByUserId;
326
+ }
327
+
328
+ public void setUpdatedByUserId(UUID updatedByUserId) {
329
+ this.updatedByUserId = updatedByUserId;
330
+ }
331
+
332
+ @Override
333
+ public String toString() {
334
+ return "EventRuleOutputDTO{" +
335
+ "id=" + id +
336
+ ", name='" + name + '\'' +
337
+ ", condition='" + condition + '\'' +
338
+ ", priority=" + priority +
339
+ ", enabled=" + enabled +
340
+ '}';
341
+ }
342
+ }
343
+ }
src/main/java/com/dalab/policyengine/dto/PolicyDraftActionDTO.java ADDED
@@ -0,0 +1,268 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.dto;
2
+
3
+ import jakarta.validation.constraints.NotBlank;
4
+ import jakarta.validation.constraints.Size;
5
+
6
+ /**
7
+ * DTO for policy draft workflow actions (submit, approve, reject, etc.).
8
+ * Used for all workflow transition operations.
9
+ */
10
+ public class PolicyDraftActionDTO {
11
+
12
+ /**
13
+ * The action to perform (SUBMIT, APPROVE, REJECT, REQUEST_CHANGES, ARCHIVE).
14
+ */
15
+ @NotBlank(message = "Action type is required")
16
+ private String actionType;
17
+
18
+ /**
19
+ * Comment or reason for the action (required for rejection and optional for others).
20
+ */
21
+ @Size(max = 2000, message = "Comment must not exceed 2000 characters")
22
+ private String comment;
23
+
24
+ /**
25
+ * Priority level if submitting or approving (HIGH, MEDIUM, LOW).
26
+ */
27
+ private String priority;
28
+
29
+ /**
30
+ * Target implementation date if approving for publication.
31
+ */
32
+ private String targetImplementationDate;
33
+
34
+ /**
35
+ * Additional metadata for the action.
36
+ */
37
+ private String metadata;
38
+
39
+ // Constructors
40
+ public PolicyDraftActionDTO() {}
41
+
42
+ public PolicyDraftActionDTO(String actionType) {
43
+ this.actionType = actionType;
44
+ }
45
+
46
+ public PolicyDraftActionDTO(String actionType, String comment) {
47
+ this.actionType = actionType;
48
+ this.comment = comment;
49
+ }
50
+
51
+ // Getters and Setters
52
+ public String getActionType() {
53
+ return actionType;
54
+ }
55
+
56
+ public void setActionType(String actionType) {
57
+ this.actionType = actionType;
58
+ }
59
+
60
+ public String getComment() {
61
+ return comment;
62
+ }
63
+
64
+ public void setComment(String comment) {
65
+ this.comment = comment;
66
+ }
67
+
68
+ public String getPriority() {
69
+ return priority;
70
+ }
71
+
72
+ public void setPriority(String priority) {
73
+ this.priority = priority;
74
+ }
75
+
76
+ public String getTargetImplementationDate() {
77
+ return targetImplementationDate;
78
+ }
79
+
80
+ public void setTargetImplementationDate(String targetImplementationDate) {
81
+ this.targetImplementationDate = targetImplementationDate;
82
+ }
83
+
84
+ public String getMetadata() {
85
+ return metadata;
86
+ }
87
+
88
+ public void setMetadata(String metadata) {
89
+ this.metadata = metadata;
90
+ }
91
+ }
92
+
93
+ /**
94
+ * DTO for bulk operations on multiple policy drafts.
95
+ */
96
+ class PolicyDraftBulkActionDTO {
97
+
98
+ /**
99
+ * List of draft IDs to perform action on.
100
+ */
101
+ @NotBlank(message = "Draft IDs are required")
102
+ private java.util.List<java.util.UUID> draftIds;
103
+
104
+ /**
105
+ * The action to perform on all selected drafts.
106
+ */
107
+ @NotBlank(message = "Action type is required")
108
+ private String actionType;
109
+
110
+ /**
111
+ * Comment for the bulk action.
112
+ */
113
+ @Size(max = 1000, message = "Comment must not exceed 1000 characters")
114
+ private String comment;
115
+
116
+ // Constructors
117
+ public PolicyDraftBulkActionDTO() {}
118
+
119
+ // Getters and Setters
120
+ public java.util.List<java.util.UUID> getDraftIds() {
121
+ return draftIds;
122
+ }
123
+
124
+ public void setDraftIds(java.util.List<java.util.UUID> draftIds) {
125
+ this.draftIds = draftIds;
126
+ }
127
+
128
+ public String getActionType() {
129
+ return actionType;
130
+ }
131
+
132
+ public void setActionType(String actionType) {
133
+ this.actionType = actionType;
134
+ }
135
+
136
+ public String getComment() {
137
+ return comment;
138
+ }
139
+
140
+ public void setComment(String comment) {
141
+ this.comment = comment;
142
+ }
143
+ }
144
+
145
+ /**
146
+ * DTO for policy draft summary information (for list views).
147
+ */
148
+ class PolicyDraftSummaryDTO {
149
+
150
+ private java.util.UUID id;
151
+ private String name;
152
+ private String status;
153
+ private Integer version;
154
+ private String priority;
155
+ private String category;
156
+ private java.time.Instant createdAt;
157
+ private java.time.Instant updatedAt;
158
+ private java.util.UUID createdByUserId;
159
+ private java.time.Instant targetImplementationDate;
160
+ private int reviewCommentsCount;
161
+ private boolean isOverdue;
162
+
163
+ // Constructors
164
+ public PolicyDraftSummaryDTO() {}
165
+
166
+ public PolicyDraftSummaryDTO(java.util.UUID id, String name, String status) {
167
+ this.id = id;
168
+ this.name = name;
169
+ this.status = status;
170
+ }
171
+
172
+ // Getters and Setters
173
+ public java.util.UUID getId() {
174
+ return id;
175
+ }
176
+
177
+ public void setId(java.util.UUID id) {
178
+ this.id = id;
179
+ }
180
+
181
+ public String getName() {
182
+ return name;
183
+ }
184
+
185
+ public void setName(String name) {
186
+ this.name = name;
187
+ }
188
+
189
+ public String getStatus() {
190
+ return status;
191
+ }
192
+
193
+ public void setStatus(String status) {
194
+ this.status = status;
195
+ }
196
+
197
+ public Integer getVersion() {
198
+ return version;
199
+ }
200
+
201
+ public void setVersion(Integer version) {
202
+ this.version = version;
203
+ }
204
+
205
+ public String getPriority() {
206
+ return priority;
207
+ }
208
+
209
+ public void setPriority(String priority) {
210
+ this.priority = priority;
211
+ }
212
+
213
+ public String getCategory() {
214
+ return category;
215
+ }
216
+
217
+ public void setCategory(String category) {
218
+ this.category = category;
219
+ }
220
+
221
+ public java.time.Instant getCreatedAt() {
222
+ return createdAt;
223
+ }
224
+
225
+ public void setCreatedAt(java.time.Instant createdAt) {
226
+ this.createdAt = createdAt;
227
+ }
228
+
229
+ public java.time.Instant getUpdatedAt() {
230
+ return updatedAt;
231
+ }
232
+
233
+ public void setUpdatedAt(java.time.Instant updatedAt) {
234
+ this.updatedAt = updatedAt;
235
+ }
236
+
237
+ public java.util.UUID getCreatedByUserId() {
238
+ return createdByUserId;
239
+ }
240
+
241
+ public void setCreatedByUserId(java.util.UUID createdByUserId) {
242
+ this.createdByUserId = createdByUserId;
243
+ }
244
+
245
+ public java.time.Instant getTargetImplementationDate() {
246
+ return targetImplementationDate;
247
+ }
248
+
249
+ public void setTargetImplementationDate(java.time.Instant targetImplementationDate) {
250
+ this.targetImplementationDate = targetImplementationDate;
251
+ }
252
+
253
+ public int getReviewCommentsCount() {
254
+ return reviewCommentsCount;
255
+ }
256
+
257
+ public void setReviewCommentsCount(int reviewCommentsCount) {
258
+ this.reviewCommentsCount = reviewCommentsCount;
259
+ }
260
+
261
+ public boolean isOverdue() {
262
+ return isOverdue;
263
+ }
264
+
265
+ public void setOverdue(boolean overdue) {
266
+ isOverdue = overdue;
267
+ }
268
+ }
src/main/java/com/dalab/policyengine/dto/PolicyDraftInputDTO.java ADDED
@@ -0,0 +1,227 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.dto;
2
+
3
+ import java.time.Instant;
4
+ import java.util.List;
5
+ import java.util.Map;
6
+ import java.util.UUID;
7
+
8
+ import jakarta.validation.constraints.NotBlank;
9
+ import jakarta.validation.constraints.Size;
10
+
11
+ /**
12
+ * DTO for creating and updating policy drafts.
13
+ * Contains all information needed for draft management and workflow.
14
+ */
15
+ public class PolicyDraftInputDTO {
16
+
17
+ /**
18
+ * Name of the policy (must be unique when published).
19
+ */
20
+ @NotBlank(message = "Policy name is required")
21
+ @Size(max = 255, message = "Policy name must not exceed 255 characters")
22
+ private String name;
23
+
24
+ /**
25
+ * Detailed description of the policy's purpose and scope.
26
+ */
27
+ @Size(max = 2000, message = "Description must not exceed 2000 characters")
28
+ private String description;
29
+
30
+ /**
31
+ * Reference to the published policy if this is an update.
32
+ */
33
+ private UUID basePolicyId;
34
+
35
+ /**
36
+ * MVEL condition logic for the policy evaluation.
37
+ */
38
+ private String conditionLogic;
39
+
40
+ /**
41
+ * JSON representation of policy rules structure.
42
+ */
43
+ private List<Map<String, Object>> rulesDefinition;
44
+
45
+ /**
46
+ * JSON representation of actions to be taken when policy is triggered.
47
+ */
48
+ private Map<String, Object> actions;
49
+
50
+ /**
51
+ * Change summary describing what was modified in this version.
52
+ */
53
+ @Size(max = 1000, message = "Change summary must not exceed 1000 characters")
54
+ private String changeSummary;
55
+
56
+ /**
57
+ * Justification for the policy changes or creation.
58
+ */
59
+ @Size(max = 2000, message = "Justification must not exceed 2000 characters")
60
+ private String justification;
61
+
62
+ /**
63
+ * Expected impact of implementing this policy.
64
+ */
65
+ @Size(max = 1000, message = "Expected impact must not exceed 1000 characters")
66
+ private String expectedImpact;
67
+
68
+ /**
69
+ * Target implementation date for the policy.
70
+ */
71
+ private Instant targetImplementationDate;
72
+
73
+ /**
74
+ * Priority level for policy implementation.
75
+ */
76
+ private String priority = "MEDIUM";
77
+
78
+ /**
79
+ * Business category or domain this policy applies to.
80
+ */
81
+ @Size(max = 100, message = "Category must not exceed 100 characters")
82
+ private String category;
83
+
84
+ /**
85
+ * Tags for categorization and searchability.
86
+ */
87
+ private List<String> tags;
88
+
89
+ /**
90
+ * Stakeholders who should be notified about this policy.
91
+ */
92
+ private List<UUID> stakeholders;
93
+
94
+ /**
95
+ * Additional metadata for workflow management.
96
+ */
97
+ private Map<String, Object> workflowMetadata;
98
+
99
+ // Constructors
100
+ public PolicyDraftInputDTO() {}
101
+
102
+ public PolicyDraftInputDTO(String name, String description) {
103
+ this.name = name;
104
+ this.description = description;
105
+ }
106
+
107
+ // Getters and Setters
108
+ public String getName() {
109
+ return name;
110
+ }
111
+
112
+ public void setName(String name) {
113
+ this.name = name;
114
+ }
115
+
116
+ public String getDescription() {
117
+ return description;
118
+ }
119
+
120
+ public void setDescription(String description) {
121
+ this.description = description;
122
+ }
123
+
124
+ public UUID getBasePolicyId() {
125
+ return basePolicyId;
126
+ }
127
+
128
+ public void setBasePolicyId(UUID basePolicyId) {
129
+ this.basePolicyId = basePolicyId;
130
+ }
131
+
132
+ public String getConditionLogic() {
133
+ return conditionLogic;
134
+ }
135
+
136
+ public void setConditionLogic(String conditionLogic) {
137
+ this.conditionLogic = conditionLogic;
138
+ }
139
+
140
+ public List<Map<String, Object>> getRulesDefinition() {
141
+ return rulesDefinition;
142
+ }
143
+
144
+ public void setRulesDefinition(List<Map<String, Object>> rulesDefinition) {
145
+ this.rulesDefinition = rulesDefinition;
146
+ }
147
+
148
+ public Map<String, Object> getActions() {
149
+ return actions;
150
+ }
151
+
152
+ public void setActions(Map<String, Object> actions) {
153
+ this.actions = actions;
154
+ }
155
+
156
+ public String getChangeSummary() {
157
+ return changeSummary;
158
+ }
159
+
160
+ public void setChangeSummary(String changeSummary) {
161
+ this.changeSummary = changeSummary;
162
+ }
163
+
164
+ public String getJustification() {
165
+ return justification;
166
+ }
167
+
168
+ public void setJustification(String justification) {
169
+ this.justification = justification;
170
+ }
171
+
172
+ public String getExpectedImpact() {
173
+ return expectedImpact;
174
+ }
175
+
176
+ public void setExpectedImpact(String expectedImpact) {
177
+ this.expectedImpact = expectedImpact;
178
+ }
179
+
180
+ public Instant getTargetImplementationDate() {
181
+ return targetImplementationDate;
182
+ }
183
+
184
+ public void setTargetImplementationDate(Instant targetImplementationDate) {
185
+ this.targetImplementationDate = targetImplementationDate;
186
+ }
187
+
188
+ public String getPriority() {
189
+ return priority;
190
+ }
191
+
192
+ public void setPriority(String priority) {
193
+ this.priority = priority;
194
+ }
195
+
196
+ public String getCategory() {
197
+ return category;
198
+ }
199
+
200
+ public void setCategory(String category) {
201
+ this.category = category;
202
+ }
203
+
204
+ public List<String> getTags() {
205
+ return tags;
206
+ }
207
+
208
+ public void setTags(List<String> tags) {
209
+ this.tags = tags;
210
+ }
211
+
212
+ public List<UUID> getStakeholders() {
213
+ return stakeholders;
214
+ }
215
+
216
+ public void setStakeholders(List<UUID> stakeholders) {
217
+ this.stakeholders = stakeholders;
218
+ }
219
+
220
+ public Map<String, Object> getWorkflowMetadata() {
221
+ return workflowMetadata;
222
+ }
223
+
224
+ public void setWorkflowMetadata(Map<String, Object> workflowMetadata) {
225
+ this.workflowMetadata = workflowMetadata;
226
+ }
227
+ }
src/main/java/com/dalab/policyengine/dto/PolicyDraftOutputDTO.java ADDED
@@ -0,0 +1,412 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.dto;
2
+
3
+ import java.time.Instant;
4
+ import java.util.List;
5
+ import java.util.Map;
6
+ import java.util.UUID;
7
+
8
+ /**
9
+ * DTO for returning policy draft information including workflow status and audit trail.
10
+ * Contains comprehensive information for UI display and workflow management.
11
+ */
12
+ public class PolicyDraftOutputDTO {
13
+
14
+ private UUID id;
15
+ private String name;
16
+ private String description;
17
+ private String status;
18
+ private Integer version;
19
+ private UUID basePolicyId;
20
+ private String conditionLogic;
21
+ private List<Map<String, Object>> rulesDefinition;
22
+ private Map<String, Object> actions;
23
+ private String changeSummary;
24
+ private String justification;
25
+ private String expectedImpact;
26
+ private Instant targetImplementationDate;
27
+ private String priority;
28
+ private String category;
29
+ private List<String> tags;
30
+ private List<UUID> stakeholders;
31
+ private Map<String, Object> approvalMetadata;
32
+ private List<Map<String, Object>> reviewComments;
33
+
34
+ // Audit trail information
35
+ private Instant createdAt;
36
+ private Instant updatedAt;
37
+ private UUID createdByUserId;
38
+ private UUID updatedByUserId;
39
+ private Instant submittedAt;
40
+ private UUID submittedByUserId;
41
+ private Instant approvedAt;
42
+ private UUID approvedByUserId;
43
+ private Instant rejectedAt;
44
+ private UUID rejectedByUserId;
45
+ private Instant publishedAt;
46
+ private UUID publishedByUserId;
47
+
48
+ // Enhanced workflow information
49
+ private WorkflowStatusDTO workflowStatus;
50
+ private List<WorkflowActionDTO> availableActions;
51
+
52
+ // Constructors
53
+ public PolicyDraftOutputDTO() {}
54
+
55
+ public PolicyDraftOutputDTO(UUID id, String name, String status) {
56
+ this.id = id;
57
+ this.name = name;
58
+ this.status = status;
59
+ }
60
+
61
+ // Getters and Setters
62
+ public UUID getId() {
63
+ return id;
64
+ }
65
+
66
+ public void setId(UUID id) {
67
+ this.id = id;
68
+ }
69
+
70
+ public String getName() {
71
+ return name;
72
+ }
73
+
74
+ public void setName(String name) {
75
+ this.name = name;
76
+ }
77
+
78
+ public String getDescription() {
79
+ return description;
80
+ }
81
+
82
+ public void setDescription(String description) {
83
+ this.description = description;
84
+ }
85
+
86
+ public String getStatus() {
87
+ return status;
88
+ }
89
+
90
+ public void setStatus(String status) {
91
+ this.status = status;
92
+ }
93
+
94
+ public Integer getVersion() {
95
+ return version;
96
+ }
97
+
98
+ public void setVersion(Integer version) {
99
+ this.version = version;
100
+ }
101
+
102
+ public UUID getBasePolicyId() {
103
+ return basePolicyId;
104
+ }
105
+
106
+ public void setBasePolicyId(UUID basePolicyId) {
107
+ this.basePolicyId = basePolicyId;
108
+ }
109
+
110
+ public String getConditionLogic() {
111
+ return conditionLogic;
112
+ }
113
+
114
+ public void setConditionLogic(String conditionLogic) {
115
+ this.conditionLogic = conditionLogic;
116
+ }
117
+
118
+ public List<Map<String, Object>> getRulesDefinition() {
119
+ return rulesDefinition;
120
+ }
121
+
122
+ public void setRulesDefinition(List<Map<String, Object>> rulesDefinition) {
123
+ this.rulesDefinition = rulesDefinition;
124
+ }
125
+
126
+ public Map<String, Object> getActions() {
127
+ return actions;
128
+ }
129
+
130
+ public void setActions(Map<String, Object> actions) {
131
+ this.actions = actions;
132
+ }
133
+
134
+ public String getChangeSummary() {
135
+ return changeSummary;
136
+ }
137
+
138
+ public void setChangeSummary(String changeSummary) {
139
+ this.changeSummary = changeSummary;
140
+ }
141
+
142
+ public String getJustification() {
143
+ return justification;
144
+ }
145
+
146
+ public void setJustification(String justification) {
147
+ this.justification = justification;
148
+ }
149
+
150
+ public String getExpectedImpact() {
151
+ return expectedImpact;
152
+ }
153
+
154
+ public void setExpectedImpact(String expectedImpact) {
155
+ this.expectedImpact = expectedImpact;
156
+ }
157
+
158
+ public Instant getTargetImplementationDate() {
159
+ return targetImplementationDate;
160
+ }
161
+
162
+ public void setTargetImplementationDate(Instant targetImplementationDate) {
163
+ this.targetImplementationDate = targetImplementationDate;
164
+ }
165
+
166
+ public String getPriority() {
167
+ return priority;
168
+ }
169
+
170
+ public void setPriority(String priority) {
171
+ this.priority = priority;
172
+ }
173
+
174
+ public String getCategory() {
175
+ return category;
176
+ }
177
+
178
+ public void setCategory(String category) {
179
+ this.category = category;
180
+ }
181
+
182
+ public List<String> getTags() {
183
+ return tags;
184
+ }
185
+
186
+ public void setTags(List<String> tags) {
187
+ this.tags = tags;
188
+ }
189
+
190
+ public List<UUID> getStakeholders() {
191
+ return stakeholders;
192
+ }
193
+
194
+ public void setStakeholders(List<UUID> stakeholders) {
195
+ this.stakeholders = stakeholders;
196
+ }
197
+
198
+ public Map<String, Object> getApprovalMetadata() {
199
+ return approvalMetadata;
200
+ }
201
+
202
+ public void setApprovalMetadata(Map<String, Object> approvalMetadata) {
203
+ this.approvalMetadata = approvalMetadata;
204
+ }
205
+
206
+ public List<Map<String, Object>> getReviewComments() {
207
+ return reviewComments;
208
+ }
209
+
210
+ public void setReviewComments(List<Map<String, Object>> reviewComments) {
211
+ this.reviewComments = reviewComments;
212
+ }
213
+
214
+ public Instant getCreatedAt() {
215
+ return createdAt;
216
+ }
217
+
218
+ public void setCreatedAt(Instant createdAt) {
219
+ this.createdAt = createdAt;
220
+ }
221
+
222
+ public Instant getUpdatedAt() {
223
+ return updatedAt;
224
+ }
225
+
226
+ public void setUpdatedAt(Instant updatedAt) {
227
+ this.updatedAt = updatedAt;
228
+ }
229
+
230
+ public UUID getCreatedByUserId() {
231
+ return createdByUserId;
232
+ }
233
+
234
+ public void setCreatedByUserId(UUID createdByUserId) {
235
+ this.createdByUserId = createdByUserId;
236
+ }
237
+
238
+ public UUID getUpdatedByUserId() {
239
+ return updatedByUserId;
240
+ }
241
+
242
+ public void setUpdatedByUserId(UUID updatedByUserId) {
243
+ this.updatedByUserId = updatedByUserId;
244
+ }
245
+
246
+ public Instant getSubmittedAt() {
247
+ return submittedAt;
248
+ }
249
+
250
+ public void setSubmittedAt(Instant submittedAt) {
251
+ this.submittedAt = submittedAt;
252
+ }
253
+
254
+ public UUID getSubmittedByUserId() {
255
+ return submittedByUserId;
256
+ }
257
+
258
+ public void setSubmittedByUserId(UUID submittedByUserId) {
259
+ this.submittedByUserId = submittedByUserId;
260
+ }
261
+
262
+ public Instant getApprovedAt() {
263
+ return approvedAt;
264
+ }
265
+
266
+ public void setApprovedAt(Instant approvedAt) {
267
+ this.approvedAt = approvedAt;
268
+ }
269
+
270
+ public UUID getApprovedByUserId() {
271
+ return approvedByUserId;
272
+ }
273
+
274
+ public void setApprovedByUserId(UUID approvedByUserId) {
275
+ this.approvedByUserId = approvedByUserId;
276
+ }
277
+
278
+ public Instant getRejectedAt() {
279
+ return rejectedAt;
280
+ }
281
+
282
+ public void setRejectedAt(Instant rejectedAt) {
283
+ this.rejectedAt = rejectedAt;
284
+ }
285
+
286
+ public UUID getRejectedByUserId() {
287
+ return rejectedByUserId;
288
+ }
289
+
290
+ public void setRejectedByUserId(UUID rejectedByUserId) {
291
+ this.rejectedByUserId = rejectedByUserId;
292
+ }
293
+
294
+ public Instant getPublishedAt() {
295
+ return publishedAt;
296
+ }
297
+
298
+ public void setPublishedAt(Instant publishedAt) {
299
+ this.publishedAt = publishedAt;
300
+ }
301
+
302
+ public UUID getPublishedByUserId() {
303
+ return publishedByUserId;
304
+ }
305
+
306
+ public void setPublishedByUserId(UUID publishedByUserId) {
307
+ this.publishedByUserId = publishedByUserId;
308
+ }
309
+
310
+ public WorkflowStatusDTO getWorkflowStatus() {
311
+ return workflowStatus;
312
+ }
313
+
314
+ public void setWorkflowStatus(WorkflowStatusDTO workflowStatus) {
315
+ this.workflowStatus = workflowStatus;
316
+ }
317
+
318
+ public List<WorkflowActionDTO> getAvailableActions() {
319
+ return availableActions;
320
+ }
321
+
322
+ public void setAvailableActions(List<WorkflowActionDTO> availableActions) {
323
+ this.availableActions = availableActions;
324
+ }
325
+
326
+ /**
327
+ * Nested DTO for workflow status information.
328
+ */
329
+ public static class WorkflowStatusDTO {
330
+ private String currentStage;
331
+ private String statusDescription;
332
+ private List<String> nextPossibleStates;
333
+ private boolean canEdit;
334
+ private boolean canSubmit;
335
+ private boolean canApprove;
336
+ private boolean canReject;
337
+ private boolean canPublish;
338
+ private String stageColor; // For UI status indicators
339
+ private Integer daysInCurrentStatus;
340
+
341
+ // Constructors, getters, and setters
342
+ public WorkflowStatusDTO() {}
343
+
344
+ public String getCurrentStage() { return currentStage; }
345
+ public void setCurrentStage(String currentStage) { this.currentStage = currentStage; }
346
+
347
+ public String getStatusDescription() { return statusDescription; }
348
+ public void setStatusDescription(String statusDescription) { this.statusDescription = statusDescription; }
349
+
350
+ public List<String> getNextPossibleStates() { return nextPossibleStates; }
351
+ public void setNextPossibleStates(List<String> nextPossibleStates) { this.nextPossibleStates = nextPossibleStates; }
352
+
353
+ public boolean isCanEdit() { return canEdit; }
354
+ public void setCanEdit(boolean canEdit) { this.canEdit = canEdit; }
355
+
356
+ public boolean isCanSubmit() { return canSubmit; }
357
+ public void setCanSubmit(boolean canSubmit) { this.canSubmit = canSubmit; }
358
+
359
+ public boolean isCanApprove() { return canApprove; }
360
+ public void setCanApprove(boolean canApprove) { this.canApprove = canApprove; }
361
+
362
+ public boolean isCanReject() { return canReject; }
363
+ public void setCanReject(boolean canReject) { this.canReject = canReject; }
364
+
365
+ public boolean isCanPublish() { return canPublish; }
366
+ public void setCanPublish(boolean canPublish) { this.canPublish = canPublish; }
367
+
368
+ public String getStageColor() { return stageColor; }
369
+ public void setStageColor(String stageColor) { this.stageColor = stageColor; }
370
+
371
+ public Integer getDaysInCurrentStatus() { return daysInCurrentStatus; }
372
+ public void setDaysInCurrentStatus(Integer daysInCurrentStatus) { this.daysInCurrentStatus = daysInCurrentStatus; }
373
+ }
374
+
375
+ /**
376
+ * Nested DTO for available workflow actions.
377
+ */
378
+ public static class WorkflowActionDTO {
379
+ private String actionType;
380
+ private String actionLabel;
381
+ private String actionDescription;
382
+ private boolean requiresComment;
383
+ private String confirmationMessage;
384
+ private String buttonStyle; // For UI styling
385
+
386
+ // Constructors, getters, and setters
387
+ public WorkflowActionDTO() {}
388
+
389
+ public WorkflowActionDTO(String actionType, String actionLabel) {
390
+ this.actionType = actionType;
391
+ this.actionLabel = actionLabel;
392
+ }
393
+
394
+ public String getActionType() { return actionType; }
395
+ public void setActionType(String actionType) { this.actionType = actionType; }
396
+
397
+ public String getActionLabel() { return actionLabel; }
398
+ public void setActionLabel(String actionLabel) { this.actionLabel = actionLabel; }
399
+
400
+ public String getActionDescription() { return actionDescription; }
401
+ public void setActionDescription(String actionDescription) { this.actionDescription = actionDescription; }
402
+
403
+ public boolean isRequiresComment() { return requiresComment; }
404
+ public void setRequiresComment(boolean requiresComment) { this.requiresComment = requiresComment; }
405
+
406
+ public String getConfirmationMessage() { return confirmationMessage; }
407
+ public void setConfirmationMessage(String confirmationMessage) { this.confirmationMessage = confirmationMessage; }
408
+
409
+ public String getButtonStyle() { return buttonStyle; }
410
+ public void setButtonStyle(String buttonStyle) { this.buttonStyle = buttonStyle; }
411
+ }
412
+ }
src/main/java/com/dalab/policyengine/dto/PolicyEvaluationOutputDTO.java ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.dto;
2
+
3
+ import java.time.Instant;
4
+ import java.util.Map;
5
+ import java.util.UUID;
6
+
7
+ import com.dalab.policyengine.model.PolicyEvaluationStatus;
8
+
9
+ public class PolicyEvaluationOutputDTO {
10
+ private UUID id;
11
+ private UUID policyId;
12
+ private String policyName; // For convenience
13
+ private String targetAssetId;
14
+ private PolicyEvaluationStatus status;
15
+ private Map<String, Object> evaluationDetails; // e.g., facts used, rules evaluated, outcome per rule
16
+ private Map<String, Object> triggeredActions; // Actions taken based on the policy
17
+ private Instant evaluatedAt;
18
+ private UUID evaluationTriggeredByUserId;
19
+
20
+ // Getters and Setters
21
+ public UUID getId() {
22
+ return id;
23
+ }
24
+
25
+ public void setId(UUID id) {
26
+ this.id = id;
27
+ }
28
+
29
+ public UUID getPolicyId() {
30
+ return policyId;
31
+ }
32
+
33
+ public void setPolicyId(UUID policyId) {
34
+ this.policyId = policyId;
35
+ }
36
+
37
+ public String getPolicyName() {
38
+ return policyName;
39
+ }
40
+
41
+ public void setPolicyName(String policyName) {
42
+ this.policyName = policyName;
43
+ }
44
+
45
+ public String getTargetAssetId() {
46
+ return targetAssetId;
47
+ }
48
+
49
+ public void setTargetAssetId(String targetAssetId) {
50
+ this.targetAssetId = targetAssetId;
51
+ }
52
+
53
+ public PolicyEvaluationStatus getStatus() {
54
+ return status;
55
+ }
56
+
57
+ public void setStatus(PolicyEvaluationStatus status) {
58
+ this.status = status;
59
+ }
60
+
61
+ public Map<String, Object> getEvaluationDetails() {
62
+ return evaluationDetails;
63
+ }
64
+
65
+ public void setEvaluationDetails(Map<String, Object> evaluationDetails) {
66
+ this.evaluationDetails = evaluationDetails;
67
+ }
68
+
69
+ public Map<String, Object> getTriggeredActions() {
70
+ return triggeredActions;
71
+ }
72
+
73
+ public void setTriggeredActions(Map<String, Object> triggeredActions) {
74
+ this.triggeredActions = triggeredActions;
75
+ }
76
+
77
+ public Instant getEvaluatedAt() {
78
+ return evaluatedAt;
79
+ }
80
+
81
+ public void setEvaluatedAt(Instant evaluatedAt) {
82
+ this.evaluatedAt = evaluatedAt;
83
+ }
84
+
85
+ public UUID getEvaluationTriggeredByUserId() {
86
+ return evaluationTriggeredByUserId;
87
+ }
88
+
89
+ public void setEvaluationTriggeredByUserId(UUID evaluationTriggeredByUserId) {
90
+ this.evaluationTriggeredByUserId = evaluationTriggeredByUserId;
91
+ }
92
+ }
src/main/java/com/dalab/policyengine/dto/PolicyEvaluationRequestDTO.java ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.dto;
2
+
3
+ import java.util.Map;
4
+
5
+ import jakarta.validation.constraints.NotBlank;
6
+
7
+ public class PolicyEvaluationRequestDTO {
8
+
9
+ @NotBlank
10
+ private String targetAssetId; // The ID of the asset to be evaluated (e.g., from da-catalog)
11
+
12
+ // Optional: Additional context or facts that might not be directly part of the asset
13
+ // but are relevant for this specific evaluation.
14
+ private Map<String, Object> evaluationContext;
15
+
16
+ // Getters and Setters
17
+ public String getTargetAssetId() {
18
+ return targetAssetId;
19
+ }
20
+
21
+ public void setTargetAssetId(String targetAssetId) {
22
+ this.targetAssetId = targetAssetId;
23
+ }
24
+
25
+ public Map<String, Object> getEvaluationContext() {
26
+ return evaluationContext;
27
+ }
28
+
29
+ public void setEvaluationContext(Map<String, Object> evaluationContext) {
30
+ this.evaluationContext = evaluationContext;
31
+ }
32
+ }
src/main/java/com/dalab/policyengine/dto/PolicyEvaluationSummaryDTO.java ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.dto;
2
+
3
+ import java.time.Instant;
4
+ import java.util.UUID;
5
+
6
+ import com.dalab.policyengine.model.PolicyEvaluationStatus;
7
+
8
+ public class PolicyEvaluationSummaryDTO {
9
+ private UUID id;
10
+ private UUID policyId;
11
+ private String policyName;
12
+ private String targetAssetId;
13
+ private PolicyEvaluationStatus status;
14
+ private Instant evaluatedAt;
15
+
16
+ // Getters and Setters
17
+ public UUID getId() {
18
+ return id;
19
+ }
20
+
21
+ public void setId(UUID id) {
22
+ this.id = id;
23
+ }
24
+
25
+ public UUID getPolicyId() {
26
+ return policyId;
27
+ }
28
+
29
+ public void setPolicyId(UUID policyId) {
30
+ this.policyId = policyId;
31
+ }
32
+
33
+ public String getPolicyName() {
34
+ return policyName;
35
+ }
36
+
37
+ public void setPolicyName(String policyName) {
38
+ this.policyName = policyName;
39
+ }
40
+
41
+ public String getTargetAssetId() {
42
+ return targetAssetId;
43
+ }
44
+
45
+ public void setTargetAssetId(String targetAssetId) {
46
+ this.targetAssetId = targetAssetId;
47
+ }
48
+
49
+ public PolicyEvaluationStatus getStatus() {
50
+ return status;
51
+ }
52
+
53
+ public void setStatus(PolicyEvaluationStatus status) {
54
+ this.status = status;
55
+ }
56
+
57
+ public Instant getEvaluatedAt() {
58
+ return evaluatedAt;
59
+ }
60
+
61
+ public void setEvaluatedAt(Instant evaluatedAt) {
62
+ this.evaluatedAt = evaluatedAt;
63
+ }
64
+ }
src/main/java/com/dalab/policyengine/dto/PolicyImpactRequestDTO.java ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.dto;
2
+
3
+ import java.util.List;
4
+ import java.util.Map;
5
+
6
+ import jakarta.validation.constraints.NotBlank;
7
+
8
+ /**
9
+ * DTO for requesting policy impact analysis preview.
10
+ * This allows users to see what assets would be affected by policy changes before implementation.
11
+ */
12
+ public class PolicyImpactRequestDTO {
13
+
14
+ /**
15
+ * The policy rules content to analyze for impact (JSON format).
16
+ * Required field containing the policy rules that need impact analysis.
17
+ */
18
+ @NotBlank(message = "Policy rules content is required")
19
+ private String rulesContent;
20
+
21
+ /**
22
+ * Type of analysis to perform: FULL, QUICK, or TARGETED.
23
+ * - FULL: Comprehensive analysis across all assets
24
+ * - QUICK: Fast analysis with sampling
25
+ * - TARGETED: Analysis for specific asset types/groups
26
+ */
27
+ @NotBlank(message = "Analysis type is required")
28
+ private String analysisType;
29
+
30
+ /**
31
+ * Optional scope limitations for targeted analysis.
32
+ * Can include asset types, data sources, or specific asset IDs.
33
+ */
34
+ private PolicyImpactScopeDTO scope;
35
+
36
+ /**
37
+ * Include estimated performance impact in the analysis.
38
+ * When true, includes estimates for processing time and resource usage.
39
+ */
40
+ private Boolean includePerformanceEstimate = false;
41
+
42
+ /**
43
+ * Include cost impact analysis in the preview.
44
+ * When true, estimates potential costs of policy enforcement.
45
+ */
46
+ private Boolean includeCostImpact = false;
47
+
48
+ /**
49
+ * Include compliance impact analysis.
50
+ * When true, shows how this policy affects compliance with other policies.
51
+ */
52
+ private Boolean includeComplianceImpact = false;
53
+
54
+ /**
55
+ * Additional context parameters for policy evaluation.
56
+ * Flexible map for custom analysis parameters.
57
+ */
58
+ private Map<String, Object> contextParameters;
59
+
60
+ // Constructors
61
+ public PolicyImpactRequestDTO() {}
62
+
63
+ public PolicyImpactRequestDTO(String rulesContent, String analysisType) {
64
+ this.rulesContent = rulesContent;
65
+ this.analysisType = analysisType;
66
+ }
67
+
68
+ // Getters and Setters
69
+ public String getRulesContent() {
70
+ return rulesContent;
71
+ }
72
+
73
+ public void setRulesContent(String rulesContent) {
74
+ this.rulesContent = rulesContent;
75
+ }
76
+
77
+ public String getAnalysisType() {
78
+ return analysisType;
79
+ }
80
+
81
+ public void setAnalysisType(String analysisType) {
82
+ this.analysisType = analysisType;
83
+ }
84
+
85
+ public PolicyImpactScopeDTO getScope() {
86
+ return scope;
87
+ }
88
+
89
+ public void setScope(PolicyImpactScopeDTO scope) {
90
+ this.scope = scope;
91
+ }
92
+
93
+ public Boolean getIncludePerformanceEstimate() {
94
+ return includePerformanceEstimate;
95
+ }
96
+
97
+ public void setIncludePerformanceEstimate(Boolean includePerformanceEstimate) {
98
+ this.includePerformanceEstimate = includePerformanceEstimate;
99
+ }
100
+
101
+ public Boolean getIncludeCostImpact() {
102
+ return includeCostImpact;
103
+ }
104
+
105
+ public void setIncludeCostImpact(Boolean includeCostImpact) {
106
+ this.includeCostImpact = includeCostImpact;
107
+ }
108
+
109
+ public Boolean getIncludeComplianceImpact() {
110
+ return includeComplianceImpact;
111
+ }
112
+
113
+ public void setIncludeComplianceImpact(Boolean includeComplianceImpact) {
114
+ this.includeComplianceImpact = includeComplianceImpact;
115
+ }
116
+
117
+ public Map<String, Object> getContextParameters() {
118
+ return contextParameters;
119
+ }
120
+
121
+ public void setContextParameters(Map<String, Object> contextParameters) {
122
+ this.contextParameters = contextParameters;
123
+ }
124
+
125
+ /**
126
+ * Nested DTO for defining analysis scope limitations.
127
+ */
128
+ public static class PolicyImpactScopeDTO {
129
+ /**
130
+ * Specific asset types to include in analysis (e.g., "database", "file", "api").
131
+ */
132
+ private List<String> assetTypes;
133
+
134
+ /**
135
+ * Specific data sources to include (e.g., connection IDs or source names).
136
+ */
137
+ private List<String> dataSources;
138
+
139
+ /**
140
+ * Specific asset IDs to analyze (for targeted analysis).
141
+ */
142
+ private List<String> assetIds;
143
+
144
+ /**
145
+ * Include only assets with specific labels.
146
+ */
147
+ private List<String> requiredLabels;
148
+
149
+ /**
150
+ * Exclude assets with specific labels.
151
+ */
152
+ private List<String> excludedLabels;
153
+
154
+ /**
155
+ * Maximum number of assets to analyze (for performance control).
156
+ */
157
+ private Integer maxAssets;
158
+
159
+ // Constructors
160
+ public PolicyImpactScopeDTO() {}
161
+
162
+ // Getters and Setters
163
+ public List<String> getAssetTypes() {
164
+ return assetTypes;
165
+ }
166
+
167
+ public void setAssetTypes(List<String> assetTypes) {
168
+ this.assetTypes = assetTypes;
169
+ }
170
+
171
+ public List<String> getDataSources() {
172
+ return dataSources;
173
+ }
174
+
175
+ public void setDataSources(List<String> dataSources) {
176
+ this.dataSources = dataSources;
177
+ }
178
+
179
+ public List<String> getAssetIds() {
180
+ return assetIds;
181
+ }
182
+
183
+ public void setAssetIds(List<String> assetIds) {
184
+ this.assetIds = assetIds;
185
+ }
186
+
187
+ public List<String> getRequiredLabels() {
188
+ return requiredLabels;
189
+ }
190
+
191
+ public void setRequiredLabels(List<String> requiredLabels) {
192
+ this.requiredLabels = requiredLabels;
193
+ }
194
+
195
+ public List<String> getExcludedLabels() {
196
+ return excludedLabels;
197
+ }
198
+
199
+ public void setExcludedLabels(List<String> excludedLabels) {
200
+ this.excludedLabels = excludedLabels;
201
+ }
202
+
203
+ public Integer getMaxAssets() {
204
+ return maxAssets;
205
+ }
206
+
207
+ public void setMaxAssets(Integer maxAssets) {
208
+ this.maxAssets = maxAssets;
209
+ }
210
+ }
211
+ }
src/main/java/com/dalab/policyengine/dto/PolicyImpactResponseDTO.java ADDED
@@ -0,0 +1,376 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.dto;
2
+
3
+ import java.time.Instant;
4
+ import java.util.List;
5
+ import java.util.Map;
6
+
7
+ /**
8
+ * Comprehensive DTO for policy impact analysis response.
9
+ * Contains detailed analysis of what assets would be affected by policy changes.
10
+ */
11
+ public class PolicyImpactResponseDTO {
12
+
13
+ /**
14
+ * Unique identifier for this impact analysis.
15
+ */
16
+ private String analysisId;
17
+
18
+ /**
19
+ * Timestamp when the analysis was performed.
20
+ */
21
+ private Instant analyzedAt;
22
+
23
+ /**
24
+ * Type of analysis performed: FULL, QUICK, or TARGETED.
25
+ */
26
+ private String analysisType;
27
+
28
+ /**
29
+ * Overall impact summary with key metrics.
30
+ */
31
+ private ImpactSummaryDTO summary;
32
+
33
+ /**
34
+ * Detailed breakdown of affected assets by category.
35
+ */
36
+ private List<AssetImpactDTO> affectedAssets;
37
+
38
+ /**
39
+ * Performance impact estimates (if requested).
40
+ */
41
+ private PerformanceImpactDTO performanceImpact;
42
+
43
+ /**
44
+ * Cost impact analysis (if requested).
45
+ */
46
+ private CostImpactDTO costImpact;
47
+
48
+ /**
49
+ * Compliance impact analysis (if requested).
50
+ */
51
+ private ComplianceImpactDTO complianceImpact;
52
+
53
+ /**
54
+ * Risk assessment for implementing this policy.
55
+ */
56
+ private RiskAssessmentDTO riskAssessment;
57
+
58
+ /**
59
+ * Recommendations for policy implementation.
60
+ */
61
+ private List<String> recommendations;
62
+
63
+ /**
64
+ * Analysis execution metadata.
65
+ */
66
+ private AnalysisMetadataDTO metadata;
67
+
68
+ // Constructors
69
+ public PolicyImpactResponseDTO() {}
70
+
71
+ public PolicyImpactResponseDTO(String analysisId, String analysisType) {
72
+ this.analysisId = analysisId;
73
+ this.analysisType = analysisType;
74
+ this.analyzedAt = Instant.now();
75
+ }
76
+
77
+ // Getters and Setters
78
+ public String getAnalysisId() {
79
+ return analysisId;
80
+ }
81
+
82
+ public void setAnalysisId(String analysisId) {
83
+ this.analysisId = analysisId;
84
+ }
85
+
86
+ public Instant getAnalyzedAt() {
87
+ return analyzedAt;
88
+ }
89
+
90
+ public void setAnalyzedAt(Instant analyzedAt) {
91
+ this.analyzedAt = analyzedAt;
92
+ }
93
+
94
+ public String getAnalysisType() {
95
+ return analysisType;
96
+ }
97
+
98
+ public void setAnalysisType(String analysisType) {
99
+ this.analysisType = analysisType;
100
+ }
101
+
102
+ public ImpactSummaryDTO getSummary() {
103
+ return summary;
104
+ }
105
+
106
+ public void setSummary(ImpactSummaryDTO summary) {
107
+ this.summary = summary;
108
+ }
109
+
110
+ public List<AssetImpactDTO> getAffectedAssets() {
111
+ return affectedAssets;
112
+ }
113
+
114
+ public void setAffectedAssets(List<AssetImpactDTO> affectedAssets) {
115
+ this.affectedAssets = affectedAssets;
116
+ }
117
+
118
+ public PerformanceImpactDTO getPerformanceImpact() {
119
+ return performanceImpact;
120
+ }
121
+
122
+ public void setPerformanceImpact(PerformanceImpactDTO performanceImpact) {
123
+ this.performanceImpact = performanceImpact;
124
+ }
125
+
126
+ public CostImpactDTO getCostImpact() {
127
+ return costImpact;
128
+ }
129
+
130
+ public void setCostImpact(CostImpactDTO costImpact) {
131
+ this.costImpact = costImpact;
132
+ }
133
+
134
+ public ComplianceImpactDTO getComplianceImpact() {
135
+ return complianceImpact;
136
+ }
137
+
138
+ public void setComplianceImpact(ComplianceImpactDTO complianceImpact) {
139
+ this.complianceImpact = complianceImpact;
140
+ }
141
+
142
+ public RiskAssessmentDTO getRiskAssessment() {
143
+ return riskAssessment;
144
+ }
145
+
146
+ public void setRiskAssessment(RiskAssessmentDTO riskAssessment) {
147
+ this.riskAssessment = riskAssessment;
148
+ }
149
+
150
+ public List<String> getRecommendations() {
151
+ return recommendations;
152
+ }
153
+
154
+ public void setRecommendations(List<String> recommendations) {
155
+ this.recommendations = recommendations;
156
+ }
157
+
158
+ public AnalysisMetadataDTO getMetadata() {
159
+ return metadata;
160
+ }
161
+
162
+ public void setMetadata(AnalysisMetadataDTO metadata) {
163
+ this.metadata = metadata;
164
+ }
165
+
166
+ /**
167
+ * Overall impact summary with key metrics.
168
+ */
169
+ public static class ImpactSummaryDTO {
170
+ private Integer totalAssetsAnalyzed;
171
+ private Integer totalAssetsAffected;
172
+ private Integer highImpactAssets;
173
+ private Integer mediumImpactAssets;
174
+ private Integer lowImpactAssets;
175
+ private String overallRiskLevel; // LOW, MEDIUM, HIGH, CRITICAL
176
+ private Double impactPercentage;
177
+
178
+ // Constructors, getters, and setters
179
+ public ImpactSummaryDTO() {}
180
+
181
+ public Integer getTotalAssetsAnalyzed() { return totalAssetsAnalyzed; }
182
+ public void setTotalAssetsAnalyzed(Integer totalAssetsAnalyzed) { this.totalAssetsAnalyzed = totalAssetsAnalyzed; }
183
+
184
+ public Integer getTotalAssetsAffected() { return totalAssetsAffected; }
185
+ public void setTotalAssetsAffected(Integer totalAssetsAffected) { this.totalAssetsAffected = totalAssetsAffected; }
186
+
187
+ public Integer getHighImpactAssets() { return highImpactAssets; }
188
+ public void setHighImpactAssets(Integer highImpactAssets) { this.highImpactAssets = highImpactAssets; }
189
+
190
+ public Integer getMediumImpactAssets() { return mediumImpactAssets; }
191
+ public void setMediumImpactAssets(Integer mediumImpactAssets) { this.mediumImpactAssets = mediumImpactAssets; }
192
+
193
+ public Integer getLowImpactAssets() { return lowImpactAssets; }
194
+ public void setLowImpactAssets(Integer lowImpactAssets) { this.lowImpactAssets = lowImpactAssets; }
195
+
196
+ public String getOverallRiskLevel() { return overallRiskLevel; }
197
+ public void setOverallRiskLevel(String overallRiskLevel) { this.overallRiskLevel = overallRiskLevel; }
198
+
199
+ public Double getImpactPercentage() { return impactPercentage; }
200
+ public void setImpactPercentage(Double impactPercentage) { this.impactPercentage = impactPercentage; }
201
+ }
202
+
203
+ /**
204
+ * Individual asset impact details.
205
+ */
206
+ public static class AssetImpactDTO {
207
+ private String assetId;
208
+ private String assetName;
209
+ private String assetType;
210
+ private String impactLevel; // HIGH, MEDIUM, LOW
211
+ private List<String> affectedAttributes;
212
+ private List<String> appliedActions;
213
+ private String riskAssessment;
214
+ private Map<String, Object> impactDetails;
215
+
216
+ // Constructors, getters, and setters
217
+ public AssetImpactDTO() {}
218
+
219
+ public String getAssetId() { return assetId; }
220
+ public void setAssetId(String assetId) { this.assetId = assetId; }
221
+
222
+ public String getAssetName() { return assetName; }
223
+ public void setAssetName(String assetName) { this.assetName = assetName; }
224
+
225
+ public String getAssetType() { return assetType; }
226
+ public void setAssetType(String assetType) { this.assetType = assetType; }
227
+
228
+ public String getImpactLevel() { return impactLevel; }
229
+ public void setImpactLevel(String impactLevel) { this.impactLevel = impactLevel; }
230
+
231
+ public List<String> getAffectedAttributes() { return affectedAttributes; }
232
+ public void setAffectedAttributes(List<String> affectedAttributes) { this.affectedAttributes = affectedAttributes; }
233
+
234
+ public List<String> getAppliedActions() { return appliedActions; }
235
+ public void setAppliedActions(List<String> appliedActions) { this.appliedActions = appliedActions; }
236
+
237
+ public String getRiskAssessment() { return riskAssessment; }
238
+ public void setRiskAssessment(String riskAssessment) { this.riskAssessment = riskAssessment; }
239
+
240
+ public Map<String, Object> getImpactDetails() { return impactDetails; }
241
+ public void setImpactDetails(Map<String, Object> impactDetails) { this.impactDetails = impactDetails; }
242
+ }
243
+
244
+ /**
245
+ * Performance impact estimates.
246
+ */
247
+ public static class PerformanceImpactDTO {
248
+ private Long estimatedProcessingTimeMs;
249
+ private Double cpuUtilizationIncrease;
250
+ private Double memoryUtilizationIncrease;
251
+ private Integer estimatedApiCalls;
252
+ private String performanceRiskLevel;
253
+
254
+ // Constructors, getters, and setters
255
+ public PerformanceImpactDTO() {}
256
+
257
+ public Long getEstimatedProcessingTimeMs() { return estimatedProcessingTimeMs; }
258
+ public void setEstimatedProcessingTimeMs(Long estimatedProcessingTimeMs) { this.estimatedProcessingTimeMs = estimatedProcessingTimeMs; }
259
+
260
+ public Double getCpuUtilizationIncrease() { return cpuUtilizationIncrease; }
261
+ public void setCpuUtilizationIncrease(Double cpuUtilizationIncrease) { this.cpuUtilizationIncrease = cpuUtilizationIncrease; }
262
+
263
+ public Double getMemoryUtilizationIncrease() { return memoryUtilizationIncrease; }
264
+ public void setMemoryUtilizationIncrease(Double memoryUtilizationIncrease) { this.memoryUtilizationIncrease = memoryUtilizationIncrease; }
265
+
266
+ public Integer getEstimatedApiCalls() { return estimatedApiCalls; }
267
+ public void setEstimatedApiCalls(Integer estimatedApiCalls) { this.estimatedApiCalls = estimatedApiCalls; }
268
+
269
+ public String getPerformanceRiskLevel() { return performanceRiskLevel; }
270
+ public void setPerformanceRiskLevel(String performanceRiskLevel) { this.performanceRiskLevel = performanceRiskLevel; }
271
+ }
272
+
273
+ /**
274
+ * Cost impact analysis.
275
+ */
276
+ public static class CostImpactDTO {
277
+ private Double estimatedMonthlyCost;
278
+ private Double estimatedImplementationCost;
279
+ private Double potentialSavings;
280
+ private String costRiskLevel;
281
+ private Map<String, Double> costBreakdown;
282
+
283
+ // Constructors, getters, and setters
284
+ public CostImpactDTO() {}
285
+
286
+ public Double getEstimatedMonthlyCost() { return estimatedMonthlyCost; }
287
+ public void setEstimatedMonthlyCost(Double estimatedMonthlyCost) { this.estimatedMonthlyCost = estimatedMonthlyCost; }
288
+
289
+ public Double getEstimatedImplementationCost() { return estimatedImplementationCost; }
290
+ public void setEstimatedImplementationCost(Double estimatedImplementationCost) { this.estimatedImplementationCost = estimatedImplementationCost; }
291
+
292
+ public Double getPotentialSavings() { return potentialSavings; }
293
+ public void setPotentialSavings(Double potentialSavings) { this.potentialSavings = potentialSavings; }
294
+
295
+ public String getCostRiskLevel() { return costRiskLevel; }
296
+ public void setCostRiskLevel(String costRiskLevel) { this.costRiskLevel = costRiskLevel; }
297
+
298
+ public Map<String, Double> getCostBreakdown() { return costBreakdown; }
299
+ public void setCostBreakdown(Map<String, Double> costBreakdown) { this.costBreakdown = costBreakdown; }
300
+ }
301
+
302
+ /**
303
+ * Compliance impact analysis.
304
+ */
305
+ public static class ComplianceImpactDTO {
306
+ private Integer conflictingPolicies;
307
+ private List<String> complianceFrameworksAffected;
308
+ private String complianceRiskLevel;
309
+ private List<String> potentialViolations;
310
+
311
+ // Constructors, getters, and setters
312
+ public ComplianceImpactDTO() {}
313
+
314
+ public Integer getConflictingPolicies() { return conflictingPolicies; }
315
+ public void setConflictingPolicies(Integer conflictingPolicies) { this.conflictingPolicies = conflictingPolicies; }
316
+
317
+ public List<String> getComplianceFrameworksAffected() { return complianceFrameworksAffected; }
318
+ public void setComplianceFrameworksAffected(List<String> complianceFrameworksAffected) { this.complianceFrameworksAffected = complianceFrameworksAffected; }
319
+
320
+ public String getComplianceRiskLevel() { return complianceRiskLevel; }
321
+ public void setComplianceRiskLevel(String complianceRiskLevel) { this.complianceRiskLevel = complianceRiskLevel; }
322
+
323
+ public List<String> getPotentialViolations() { return potentialViolations; }
324
+ public void setPotentialViolations(List<String> potentialViolations) { this.potentialViolations = potentialViolations; }
325
+ }
326
+
327
+ /**
328
+ * Risk assessment for policy implementation.
329
+ */
330
+ public static class RiskAssessmentDTO {
331
+ private String overallRiskLevel;
332
+ private List<String> identifiedRisks;
333
+ private List<String> mitigationStrategies;
334
+ private Double riskScore;
335
+
336
+ // Constructors, getters, and setters
337
+ public RiskAssessmentDTO() {}
338
+
339
+ public String getOverallRiskLevel() { return overallRiskLevel; }
340
+ public void setOverallRiskLevel(String overallRiskLevel) { this.overallRiskLevel = overallRiskLevel; }
341
+
342
+ public List<String> getIdentifiedRisks() { return identifiedRisks; }
343
+ public void setIdentifiedRisks(List<String> identifiedRisks) { this.identifiedRisks = identifiedRisks; }
344
+
345
+ public List<String> getMitigationStrategies() { return mitigationStrategies; }
346
+ public void setMitigationStrategies(List<String> mitigationStrategies) { this.mitigationStrategies = mitigationStrategies; }
347
+
348
+ public Double getRiskScore() { return riskScore; }
349
+ public void setRiskScore(Double riskScore) { this.riskScore = riskScore; }
350
+ }
351
+
352
+ /**
353
+ * Analysis execution metadata.
354
+ */
355
+ public static class AnalysisMetadataDTO {
356
+ private Long executionTimeMs;
357
+ private String analysisVersion;
358
+ private Boolean usesCachedData;
359
+ private Instant dataFreshnessTimestamp;
360
+
361
+ // Constructors, getters, and setters
362
+ public AnalysisMetadataDTO() {}
363
+
364
+ public Long getExecutionTimeMs() { return executionTimeMs; }
365
+ public void setExecutionTimeMs(Long executionTimeMs) { this.executionTimeMs = executionTimeMs; }
366
+
367
+ public String getAnalysisVersion() { return analysisVersion; }
368
+ public void setAnalysisVersion(String analysisVersion) { this.analysisVersion = analysisVersion; }
369
+
370
+ public Boolean getUsesCachedData() { return usesCachedData; }
371
+ public void setUsesCachedData(Boolean usesCachedData) { this.usesCachedData = usesCachedData; }
372
+
373
+ public Instant getDataFreshnessTimestamp() { return dataFreshnessTimestamp; }
374
+ public void setDataFreshnessTimestamp(Instant dataFreshnessTimestamp) { this.dataFreshnessTimestamp = dataFreshnessTimestamp; }
375
+ }
376
+ }
src/main/java/com/dalab/policyengine/dto/PolicyInputDTO.java ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.dto;
2
+
3
+ import java.util.List;
4
+ import java.util.Map;
5
+
6
+ import com.dalab.policyengine.model.PolicyStatus;
7
+
8
+ import jakarta.validation.Valid;
9
+ import jakarta.validation.constraints.NotBlank;
10
+ import jakarta.validation.constraints.NotEmpty;
11
+ import jakarta.validation.constraints.Size;
12
+
13
+ public class PolicyInputDTO {
14
+
15
+ @NotBlank
16
+ @Size(max = 255)
17
+ private String name;
18
+
19
+ @Size(max = 1000)
20
+ private String description;
21
+
22
+ private PolicyStatus status = PolicyStatus.DISABLED;
23
+
24
+ private String conditionLogic; // e.g., "rule1 && (rule2 || rule3)"
25
+
26
+ @NotEmpty
27
+ @Valid
28
+ private List<PolicyRuleDTO> rules;
29
+
30
+ private Map<String, Object> actions; // Policy-level actions
31
+
32
+ // Getters and Setters
33
+ public String getName() {
34
+ return name;
35
+ }
36
+
37
+ public void setName(String name) {
38
+ this.name = name;
39
+ }
40
+
41
+ public String getDescription() {
42
+ return description;
43
+ }
44
+
45
+ public void setDescription(String description) {
46
+ this.description = description;
47
+ }
48
+
49
+ public PolicyStatus getStatus() {
50
+ return status;
51
+ }
52
+
53
+ public void setStatus(PolicyStatus status) {
54
+ this.status = status;
55
+ }
56
+
57
+ public String getConditionLogic() {
58
+ return conditionLogic;
59
+ }
60
+
61
+ public void setConditionLogic(String conditionLogic) {
62
+ this.conditionLogic = conditionLogic;
63
+ }
64
+
65
+ public List<PolicyRuleDTO> getRules() {
66
+ return rules;
67
+ }
68
+
69
+ public void setRules(List<PolicyRuleDTO> rules) {
70
+ this.rules = rules;
71
+ }
72
+
73
+ public Map<String, Object> getActions() {
74
+ return actions;
75
+ }
76
+
77
+ public void setActions(Map<String, Object> actions) {
78
+ this.actions = actions;
79
+ }
80
+ }
src/main/java/com/dalab/policyengine/dto/PolicyOutputDTO.java ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.dto;
2
+
3
+ import java.time.Instant;
4
+ import java.util.List;
5
+ import java.util.Map;
6
+ import java.util.UUID;
7
+
8
+ import com.dalab.policyengine.model.PolicyStatus;
9
+
10
+ public class PolicyOutputDTO {
11
+ private UUID id;
12
+ private String name;
13
+ private String description;
14
+ private PolicyStatus status;
15
+ private String conditionLogic;
16
+ private List<PolicyRuleDTO> rules;
17
+ private Map<String, Object> actions;
18
+ private Instant createdAt;
19
+ private Instant updatedAt;
20
+ private UUID createdByUserId;
21
+ private UUID updatedByUserId;
22
+
23
+ // Getters and Setters
24
+ public UUID getId() {
25
+ return id;
26
+ }
27
+
28
+ public void setId(UUID id) {
29
+ this.id = id;
30
+ }
31
+
32
+ public String getName() {
33
+ return name;
34
+ }
35
+
36
+ public void setName(String name) {
37
+ this.name = name;
38
+ }
39
+
40
+ public String getDescription() {
41
+ return description;
42
+ }
43
+
44
+ public void setDescription(String description) {
45
+ this.description = description;
46
+ }
47
+
48
+ public PolicyStatus getStatus() {
49
+ return status;
50
+ }
51
+
52
+ public void setStatus(PolicyStatus status) {
53
+ this.status = status;
54
+ }
55
+
56
+ public String getConditionLogic() {
57
+ return conditionLogic;
58
+ }
59
+
60
+ public void setConditionLogic(String conditionLogic) {
61
+ this.conditionLogic = conditionLogic;
62
+ }
63
+
64
+ public List<PolicyRuleDTO> getRules() {
65
+ return rules;
66
+ }
67
+
68
+ public void setRules(List<PolicyRuleDTO> rules) {
69
+ this.rules = rules;
70
+ }
71
+
72
+ public Map<String, Object> getActions() {
73
+ return actions;
74
+ }
75
+
76
+ public void setActions(Map<String, Object> actions) {
77
+ this.actions = actions;
78
+ }
79
+
80
+ public Instant getCreatedAt() {
81
+ return createdAt;
82
+ }
83
+
84
+ public void setCreatedAt(Instant createdAt) {
85
+ this.createdAt = createdAt;
86
+ }
87
+
88
+ public Instant getUpdatedAt() {
89
+ return updatedAt;
90
+ }
91
+
92
+ public void setUpdatedAt(Instant updatedAt) {
93
+ this.updatedAt = updatedAt;
94
+ }
95
+
96
+ public UUID getCreatedByUserId() {
97
+ return createdByUserId;
98
+ }
99
+
100
+ public void setCreatedByUserId(UUID createdByUserId) {
101
+ this.createdByUserId = createdByUserId;
102
+ }
103
+
104
+ public UUID getUpdatedByUserId() {
105
+ return updatedByUserId;
106
+ }
107
+
108
+ public void setUpdatedByUserId(UUID updatedByUserId) {
109
+ this.updatedByUserId = updatedByUserId;
110
+ }
111
+ }
src/main/java/com/dalab/policyengine/dto/PolicyRuleDTO.java ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.dto;
2
+
3
+ import java.util.Map;
4
+
5
+ import jakarta.validation.constraints.NotBlank;
6
+ import jakarta.validation.constraints.Size;
7
+
8
+ public class PolicyRuleDTO {
9
+ private String id; // UUID as String, can be null for new rules in create/update
10
+
11
+ @NotBlank
12
+ @Size(max = 255)
13
+ private String name;
14
+
15
+ @Size(max = 1000)
16
+ private String description;
17
+
18
+ @NotBlank
19
+ private String condition; // MVEL expression
20
+
21
+ private int priority = 1;
22
+ private Map<String, Object> actions; // Optional rule-specific actions
23
+
24
+ // Getters and Setters
25
+ public String getId() {
26
+ return id;
27
+ }
28
+
29
+ public void setId(String id) {
30
+ this.id = id;
31
+ }
32
+
33
+ public String getName() {
34
+ return name;
35
+ }
36
+
37
+ public void setName(String name) {
38
+ this.name = name;
39
+ }
40
+
41
+ public String getDescription() {
42
+ return description;
43
+ }
44
+
45
+ public void setDescription(String description) {
46
+ this.description = description;
47
+ }
48
+
49
+ public String getCondition() {
50
+ return condition;
51
+ }
52
+
53
+ public void setCondition(String condition) {
54
+ this.condition = condition;
55
+ }
56
+
57
+ public int getPriority() {
58
+ return priority;
59
+ }
60
+
61
+ public void setPriority(int priority) {
62
+ this.priority = priority;
63
+ }
64
+
65
+ public Map<String, Object> getActions() {
66
+ return actions;
67
+ }
68
+
69
+ public void setActions(Map<String, Object> actions) {
70
+ this.actions = actions;
71
+ }
72
+ }
src/main/java/com/dalab/policyengine/dto/PolicySummaryDTO.java ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.dto;
2
+
3
+ import java.time.Instant;
4
+ import java.util.UUID;
5
+
6
+ import com.dalab.policyengine.model.PolicyStatus;
7
+
8
+ public class PolicySummaryDTO {
9
+ private UUID id;
10
+ private String name;
11
+ private String description;
12
+ private PolicyStatus status;
13
+ private int ruleCount;
14
+ private Instant createdAt;
15
+ private Instant updatedAt;
16
+
17
+ // Getters and Setters
18
+ public UUID getId() {
19
+ return id;
20
+ }
21
+
22
+ public void setId(UUID id) {
23
+ this.id = id;
24
+ }
25
+
26
+ public String getName() {
27
+ return name;
28
+ }
29
+
30
+ public void setName(String name) {
31
+ this.name = name;
32
+ }
33
+
34
+ public String getDescription() {
35
+ return description;
36
+ }
37
+
38
+ public void setDescription(String description) {
39
+ this.description = description;
40
+ }
41
+
42
+ public PolicyStatus getStatus() {
43
+ return status;
44
+ }
45
+
46
+ public void setStatus(PolicyStatus status) {
47
+ this.status = status;
48
+ }
49
+
50
+ public int getRuleCount() {
51
+ return ruleCount;
52
+ }
53
+
54
+ public void setRuleCount(int ruleCount) {
55
+ this.ruleCount = ruleCount;
56
+ }
57
+
58
+ public Instant getCreatedAt() {
59
+ return createdAt;
60
+ }
61
+
62
+ public void setCreatedAt(Instant createdAt) {
63
+ this.createdAt = createdAt;
64
+ }
65
+
66
+ public Instant getUpdatedAt() {
67
+ return updatedAt;
68
+ }
69
+
70
+ public void setUpdatedAt(Instant updatedAt) {
71
+ this.updatedAt = updatedAt;
72
+ }
73
+ }
src/main/java/com/dalab/policyengine/event/PolicyActionEvent.java ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.event;
2
+
3
+ import java.time.Instant;
4
+ import java.util.Map;
5
+ import java.util.UUID;
6
+
7
+ // This DTO represents an action triggered by a policy evaluation,
8
+ // to be published to a Kafka topic.
9
+ public class PolicyActionEvent {
10
+ private UUID eventId;
11
+ private String policyId;
12
+ private String policyName;
13
+ private String targetAssetId;
14
+ private String actionType; // e.g., "ADD_LABEL", "NOTIFY_EMAIL", "ARCHIVE_ASSET"
15
+ private Map<String, Object> actionParameters; // Parameters for the action, e.g., {"labelName": "PII", "confidence": 0.9} or {"to": "user@example.com", "subject": "Alert"}
16
+ private Instant timestamp;
17
+ private UUID triggeredByEvaluationId; // Link back to the PolicyEvaluation record
18
+
19
+ public PolicyActionEvent() {
20
+ this.eventId = UUID.randomUUID();
21
+ this.timestamp = Instant.now();
22
+ }
23
+
24
+ // Getters and Setters
25
+ public UUID getEventId() {
26
+ return eventId;
27
+ }
28
+
29
+ public void setEventId(UUID eventId) {
30
+ this.eventId = eventId;
31
+ }
32
+
33
+ public String getPolicyId() {
34
+ return policyId;
35
+ }
36
+
37
+ public void setPolicyId(String policyId) {
38
+ this.policyId = policyId;
39
+ }
40
+
41
+ public String getPolicyName() {
42
+ return policyName;
43
+ }
44
+
45
+ public void setPolicyName(String policyName) {
46
+ this.policyName = policyName;
47
+ }
48
+
49
+ public String getTargetAssetId() {
50
+ return targetAssetId;
51
+ }
52
+
53
+ public void setTargetAssetId(String targetAssetId) {
54
+ this.targetAssetId = targetAssetId;
55
+ }
56
+
57
+ public String getActionType() {
58
+ return actionType;
59
+ }
60
+
61
+ public void setActionType(String actionType) {
62
+ this.actionType = actionType;
63
+ }
64
+
65
+ public Map<String, Object> getActionParameters() {
66
+ return actionParameters;
67
+ }
68
+
69
+ public void setActionParameters(Map<String, Object> actionParameters) {
70
+ this.actionParameters = actionParameters;
71
+ }
72
+
73
+ public Instant getTimestamp() {
74
+ return timestamp;
75
+ }
76
+
77
+ public void setTimestamp(Instant timestamp) {
78
+ this.timestamp = timestamp;
79
+ }
80
+
81
+ public UUID getTriggeredByEvaluationId() {
82
+ return triggeredByEvaluationId;
83
+ }
84
+
85
+ public void setTriggeredByEvaluationId(UUID triggeredByEvaluationId) {
86
+ this.triggeredByEvaluationId = triggeredByEvaluationId;
87
+ }
88
+
89
+ @Override
90
+ public String toString() {
91
+ return "PolicyActionEvent{" +
92
+ "eventId=" + eventId +
93
+ ", policyId='" + policyId + '\'' +
94
+ ", policyName='" + policyName + '\'' +
95
+ ", targetAssetId='" + targetAssetId + '\'' +
96
+ ", actionType='" + actionType + '\'' +
97
+ ", actionParameters=" + actionParameters +
98
+ ", timestamp=" + timestamp +
99
+ ", triggeredByEvaluationId=" + triggeredByEvaluationId +
100
+ '}';
101
+ }
102
+ }
src/main/java/com/dalab/policyengine/kafka/consumer/AssetChangeConsumer.java ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.kafka.consumer;
2
+
3
+ import java.util.UUID;
4
+
5
+ import org.slf4j.Logger;
6
+ import org.slf4j.LoggerFactory;
7
+ import org.springframework.beans.factory.annotation.Autowired;
8
+ import org.springframework.kafka.annotation.KafkaListener;
9
+ import org.springframework.messaging.handler.annotation.Payload;
10
+ import org.springframework.stereotype.Component;
11
+ import org.springframework.util.StringUtils;
12
+
13
+ // Import the common AssetChangeEvent from da-protos
14
+ import com.dalab.common.event.AssetChangeEvent;
15
+ import com.dalab.policyengine.service.IPolicyEvaluationService;
16
+
17
+ @Component
18
+ public class AssetChangeConsumer {
19
+
20
+ private static final Logger log = LoggerFactory.getLogger(AssetChangeConsumer.class);
21
+ // System UUID for actions triggered by Kafka consumer events
22
+ private static final UUID KAFKA_CONSUMER_USER_ID = UUID.fromString("00000000-0000-0000-0000-000000000001");
23
+
24
+ private final IPolicyEvaluationService policyEvaluationService;
25
+
26
+ @Autowired
27
+ public AssetChangeConsumer(IPolicyEvaluationService policyEvaluationService) {
28
+ this.policyEvaluationService = policyEvaluationService;
29
+ }
30
+
31
+ // Update KafkaListener to consume the common AssetChangeEvent
32
+ @KafkaListener(topics = "${app.kafka.topic.asset-change-event:asset-change-events}", groupId = "${spring.kafka.consumer.group-id}")
33
+ public void handleAssetChangeEvent(@Payload AssetChangeEvent event) {
34
+ log.info("Received AssetChangeEvent: AssetId={}, EventType={}", event.getAssetId(), event.getEventType());
35
+
36
+ try {
37
+ if (event == null || event.getAssetId() == null || !StringUtils.hasText(event.getAssetId())) {
38
+ log.error("AssetChangeEvent is null or missing assetId. Skipping.");
39
+ return;
40
+ }
41
+ // The PolicyEvaluationService will now fetch active policies and iterate.
42
+ policyEvaluationService.evaluatePolicyForAssetInternal(event, KAFKA_CONSUMER_USER_ID);
43
+
44
+ } catch (Exception e) {
45
+ log.error("Failed to process AssetChangeEvent for assetId {}: {}. Error: {}",
46
+ event != null && event.getAssetId() != null ? event.getAssetId() : "unknown",
47
+ e.getMessage(), e);
48
+ }
49
+ }
50
+ }
src/main/java/com/dalab/policyengine/kafka/consumer/AssetChangeEventListener.java ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.kafka.consumer;
2
+
3
+ import java.util.UUID;
4
+
5
+ import org.slf4j.Logger;
6
+ import org.slf4j.LoggerFactory;
7
+ import org.springframework.kafka.annotation.KafkaListener;
8
+ import org.springframework.kafka.support.KafkaHeaders;
9
+ import org.springframework.messaging.handler.annotation.Header;
10
+ import org.springframework.messaging.handler.annotation.Payload;
11
+ import org.springframework.stereotype.Component;
12
+
13
+ import com.dalab.common.event.AssetChangeEvent;
14
+ import com.dalab.policyengine.service.IPolicyEvaluationService;
15
+
16
+ @Component
17
+ public class AssetChangeEventListener {
18
+
19
+ private static final Logger LOGGER = LoggerFactory.getLogger(AssetChangeEventListener.class);
20
+
21
+ private final IPolicyEvaluationService policyEvaluationService;
22
+
23
+ public AssetChangeEventListener(IPolicyEvaluationService policyEvaluationService) {
24
+ this.policyEvaluationService = policyEvaluationService;
25
+ }
26
+
27
+ @KafkaListener(
28
+ topics = "#{'${app.kafka.topic.asset-change-event}'}",
29
+ groupId = "#{'${spring.kafka.consumer.group-id}'}"
30
+ // containerFactory = "assetChangeKafkaListenerContainerFactory" // If using custom factory
31
+ )
32
+ public void handleAssetChangeEvent(
33
+ @Payload AssetChangeEvent event,
34
+ @Header(KafkaHeaders.RECEIVED_TOPIC) String topic,
35
+ @Header(KafkaHeaders.RECEIVED_PARTITION) int partition,
36
+ @Header(KafkaHeaders.OFFSET) long offset
37
+ ) {
38
+ LOGGER.info(
39
+ "Received AssetChangeEvent on topic: {}, partition: {}, offset: {}: Asset ID: {}, EventType: {}",
40
+ topic, partition, offset, event.getAssetId(), event.getEventType()
41
+ );
42
+
43
+ try {
44
+ // Trigger policy evaluation based on the asset change
45
+ UUID initiatorUuid = null;
46
+ if (event.getUserId() != null && !event.getUserId().isEmpty()) {
47
+ try {
48
+ initiatorUuid = UUID.fromString(event.getUserId());
49
+ } catch (IllegalArgumentException e) {
50
+ LOGGER.warn("Could not parse userId '{}' from AssetChangeEvent to UUID. Proceeding with null initiator.", event.getUserId(), e);
51
+ }
52
+ }
53
+ policyEvaluationService.evaluatePolicyForAssetInternal(event, initiatorUuid);
54
+ LOGGER.debug("Successfully processed AssetChangeEvent for assetId: {}", event.getAssetId());
55
+ } catch (Exception e) {
56
+ // TODO: Implement proper error handling and dead-letter queue (DLQ) strategy
57
+ LOGGER.error("Error processing AssetChangeEvent for assetId: {}. Error: {}", event.getAssetId(), e.getMessage(), e);
58
+ // Depending on the error, you might rethrow to trigger Kafka's error handlers, or send to DLQ
59
+ }
60
+ }
61
+ }
src/main/java/com/dalab/policyengine/kafka/producer/PolicyActionKafkaProducer.java ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.kafka.producer;
2
+
3
+ import java.util.concurrent.CompletableFuture;
4
+
5
+ import org.slf4j.Logger;
6
+ import org.slf4j.LoggerFactory;
7
+ import org.springframework.beans.factory.annotation.Value;
8
+ import org.springframework.kafka.core.KafkaTemplate;
9
+ import org.springframework.kafka.support.SendResult;
10
+ import org.springframework.stereotype.Component;
11
+
12
+ import com.dalab.policyengine.event.PolicyActionEvent;
13
+
14
+ @Component
15
+ public class PolicyActionKafkaProducer {
16
+
17
+ private static final Logger LOGGER = LoggerFactory.getLogger(PolicyActionKafkaProducer.class);
18
+
19
+ private final KafkaTemplate<String, PolicyActionEvent> kafkaTemplate;
20
+
21
+ @Value("${app.kafka.topic.policy-action-event}")
22
+ private String topicName;
23
+
24
+ public PolicyActionKafkaProducer(KafkaTemplate<String, PolicyActionEvent> kafkaTemplate) {
25
+ this.kafkaTemplate = kafkaTemplate;
26
+ }
27
+
28
+ public void sendPolicyActionEvent(PolicyActionEvent event) {
29
+ LOGGER.info("Sending PolicyActionEvent with eventId: {} to topic: {}", event.getEventId(), topicName);
30
+
31
+ String eventKey = event.getTargetAssetId();
32
+ if (eventKey == null || eventKey.isEmpty()) {
33
+ eventKey = event.getPolicyId();
34
+ }
35
+ final String finalEventKey = eventKey;
36
+
37
+ CompletableFuture<SendResult<String, PolicyActionEvent>> future = kafkaTemplate.send(topicName, finalEventKey, event);
38
+
39
+ future.whenComplete((result, ex) -> {
40
+ if (ex == null) {
41
+ LOGGER.info(
42
+ "Successfully sent PolicyActionEvent [eventId: {}, key: {}] with offset: {}",
43
+ event.getEventId(), finalEventKey, result.getRecordMetadata().offset()
44
+ );
45
+ } else {
46
+ LOGGER.error(
47
+ "Failed to send PolicyActionEvent [eventId: {}, key: {}]: {}",
48
+ event.getEventId(), finalEventKey, ex.getMessage(), ex
49
+ );
50
+ // TODO: Handle send failure (e.g., retry, DLQ, persistent store for later retry)
51
+ }
52
+ });
53
+ }
54
+ }
src/main/java/com/dalab/policyengine/kafka/producer/PolicyActionProducer.java ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.kafka.producer;
2
+
3
+ import java.util.Map;
4
+
5
+ import org.slf4j.Logger;
6
+ import org.slf4j.LoggerFactory;
7
+ import org.springframework.beans.factory.annotation.Autowired;
8
+ import org.springframework.beans.factory.annotation.Value;
9
+ import org.springframework.kafka.core.KafkaTemplate;
10
+ import org.springframework.stereotype.Service;
11
+
12
+ @Service
13
+ public class PolicyActionProducer {
14
+
15
+ private static final Logger log = LoggerFactory.getLogger(PolicyActionProducer.class);
16
+
17
+ @Value("${app.kafka.topic.policy-action-event:policy-action-events}")
18
+ private String policyActionEventTopic;
19
+
20
+ // Use generic KafkaTemplate since we're sending Map-based events for now
21
+ private final KafkaTemplate<String, Object> kafkaTemplate;
22
+
23
+ @Autowired
24
+ public PolicyActionProducer(KafkaTemplate<String, Object> kafkaTemplate) {
25
+ this.kafkaTemplate = kafkaTemplate;
26
+ }
27
+
28
+ // Method to send policy action events as Map objects for now
29
+ public void sendPolicyActionEvent(Map<String, Object> event) {
30
+ try {
31
+ String assetId = (String) event.get("assetId");
32
+ String actionType = (String) event.get("actionType");
33
+ log.info("Sending PolicyActionEvent to topic '{}': AssetId={}, ActionType={}",
34
+ policyActionEventTopic, assetId, actionType);
35
+ // Use assetId as key for partitioning
36
+ kafkaTemplate.send(policyActionEventTopic, assetId, event);
37
+ } catch (Exception e) {
38
+ String assetId = event != null ? (String) event.get("assetId") : "unknown";
39
+ log.error("Error sending PolicyActionEvent to Kafka for assetId {}: {}", assetId, e.getMessage(), e);
40
+ }
41
+ }
42
+ }
src/main/java/com/dalab/policyengine/mapper/PolicyDraftMapper.java ADDED
@@ -0,0 +1,372 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.mapper;
2
+
3
+ import java.time.Instant;
4
+ import java.time.temporal.ChronoUnit;
5
+ import java.util.ArrayList;
6
+ import java.util.Arrays;
7
+ import java.util.List;
8
+
9
+ import org.springframework.stereotype.Component;
10
+
11
+ import com.dalab.policyengine.dto.PolicyDraftInputDTO;
12
+ import com.dalab.policyengine.dto.PolicyDraftOutputDTO;
13
+ import com.dalab.policyengine.model.PolicyDraft;
14
+ import com.dalab.policyengine.model.PolicyDraftStatus;
15
+
16
+ /**
17
+ * Mapper for converting between PolicyDraft entities and DTOs.
18
+ * Handles workflow status calculation and available actions based on current status and user permissions.
19
+ */
20
+ @Component
21
+ public class PolicyDraftMapper {
22
+
23
+ /**
24
+ * Convert PolicyDraft entity to output DTO with workflow information.
25
+ */
26
+ public PolicyDraftOutputDTO toOutputDTO(PolicyDraft draft) {
27
+ if (draft == null) {
28
+ return null;
29
+ }
30
+
31
+ PolicyDraftOutputDTO dto = new PolicyDraftOutputDTO();
32
+
33
+ // Basic information
34
+ dto.setId(draft.getId());
35
+ dto.setName(draft.getName());
36
+ dto.setDescription(draft.getDescription());
37
+ dto.setStatus(draft.getStatus().name());
38
+ dto.setVersion(draft.getVersion());
39
+ dto.setBasePolicyId(draft.getBasePolicyId());
40
+ dto.setConditionLogic(draft.getConditionLogic());
41
+ dto.setRulesDefinition(draft.getRulesDefinition());
42
+ dto.setActions(draft.getActions());
43
+ dto.setChangeSummary(draft.getChangeSummary());
44
+ dto.setJustification(draft.getJustification());
45
+ dto.setExpectedImpact(draft.getExpectedImpact());
46
+ dto.setTargetImplementationDate(draft.getTargetImplementationDate());
47
+ dto.setPriority(draft.getPriority());
48
+ dto.setCategory(draft.getCategory());
49
+ dto.setTags(draft.getTags());
50
+ dto.setStakeholders(draft.getStakeholders());
51
+ dto.setApprovalMetadata(draft.getApprovalMetadata());
52
+ dto.setReviewComments(draft.getReviewComments());
53
+
54
+ // Audit trail
55
+ dto.setCreatedAt(draft.getCreatedAt());
56
+ dto.setUpdatedAt(draft.getUpdatedAt());
57
+ dto.setCreatedByUserId(draft.getCreatedByUserId());
58
+ dto.setUpdatedByUserId(draft.getUpdatedByUserId());
59
+ dto.setSubmittedAt(draft.getSubmittedAt());
60
+ dto.setSubmittedByUserId(draft.getSubmittedByUserId());
61
+ dto.setApprovedAt(draft.getApprovedAt());
62
+ dto.setApprovedByUserId(draft.getApprovedByUserId());
63
+ dto.setRejectedAt(draft.getRejectedAt());
64
+ dto.setRejectedByUserId(draft.getRejectedByUserId());
65
+ dto.setPublishedAt(draft.getPublishedAt());
66
+ dto.setPublishedByUserId(draft.getPublishedByUserId());
67
+
68
+ // Enhanced workflow information
69
+ dto.setWorkflowStatus(createWorkflowStatus(draft));
70
+ dto.setAvailableActions(createAvailableActions(draft));
71
+
72
+ return dto;
73
+ }
74
+
75
+ /**
76
+ * Convert input DTO to PolicyDraft entity.
77
+ */
78
+ public PolicyDraft toEntity(PolicyDraftInputDTO inputDTO) {
79
+ if (inputDTO == null) {
80
+ return null;
81
+ }
82
+
83
+ PolicyDraft draft = new PolicyDraft();
84
+
85
+ draft.setName(inputDTO.getName());
86
+ draft.setDescription(inputDTO.getDescription());
87
+ draft.setBasePolicyId(inputDTO.getBasePolicyId());
88
+ draft.setConditionLogic(inputDTO.getConditionLogic());
89
+ draft.setRulesDefinition(inputDTO.getRulesDefinition());
90
+ draft.setActions(inputDTO.getActions());
91
+ draft.setChangeSummary(inputDTO.getChangeSummary());
92
+ draft.setJustification(inputDTO.getJustification());
93
+ draft.setExpectedImpact(inputDTO.getExpectedImpact());
94
+ draft.setTargetImplementationDate(inputDTO.getTargetImplementationDate());
95
+ draft.setPriority(inputDTO.getPriority());
96
+ draft.setCategory(inputDTO.getCategory());
97
+
98
+ if (inputDTO.getTags() != null) {
99
+ draft.setTags(new ArrayList<>(inputDTO.getTags()));
100
+ }
101
+ if (inputDTO.getStakeholders() != null) {
102
+ draft.setStakeholders(new ArrayList<>(inputDTO.getStakeholders()));
103
+ }
104
+
105
+ return draft;
106
+ }
107
+
108
+ /**
109
+ * Update entity from input DTO (for updates).
110
+ */
111
+ public void updateEntity(PolicyDraft draft, PolicyDraftInputDTO inputDTO) {
112
+ if (draft == null || inputDTO == null) {
113
+ return;
114
+ }
115
+
116
+ draft.setName(inputDTO.getName());
117
+ draft.setDescription(inputDTO.getDescription());
118
+ draft.setBasePolicyId(inputDTO.getBasePolicyId());
119
+ draft.setConditionLogic(inputDTO.getConditionLogic());
120
+ draft.setRulesDefinition(inputDTO.getRulesDefinition());
121
+ draft.setActions(inputDTO.getActions());
122
+ draft.setChangeSummary(inputDTO.getChangeSummary());
123
+ draft.setJustification(inputDTO.getJustification());
124
+ draft.setExpectedImpact(inputDTO.getExpectedImpact());
125
+ draft.setTargetImplementationDate(inputDTO.getTargetImplementationDate());
126
+ draft.setPriority(inputDTO.getPriority());
127
+ draft.setCategory(inputDTO.getCategory());
128
+
129
+ if (inputDTO.getTags() != null) {
130
+ draft.getTags().clear();
131
+ draft.getTags().addAll(inputDTO.getTags());
132
+ }
133
+ if (inputDTO.getStakeholders() != null) {
134
+ draft.getStakeholders().clear();
135
+ draft.getStakeholders().addAll(inputDTO.getStakeholders());
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Create workflow status information for the draft.
141
+ */
142
+ private PolicyDraftOutputDTO.WorkflowStatusDTO createWorkflowStatus(PolicyDraft draft) {
143
+ PolicyDraftOutputDTO.WorkflowStatusDTO status = new PolicyDraftOutputDTO.WorkflowStatusDTO();
144
+
145
+ PolicyDraftStatus currentStatus = draft.getStatus();
146
+ status.setCurrentStage(currentStatus.name());
147
+ status.setStatusDescription(getStatusDescription(currentStatus));
148
+ status.setNextPossibleStates(getNextPossibleStates(currentStatus));
149
+ status.setStageColor(getStageColor(currentStatus));
150
+
151
+ // Calculate days in current status
152
+ Instant statusChangeTime = getLastStatusChangeTime(draft, currentStatus);
153
+ if (statusChangeTime != null) {
154
+ long days = ChronoUnit.DAYS.between(statusChangeTime, Instant.now());
155
+ status.setDaysInCurrentStatus((int) days);
156
+ }
157
+
158
+ // Set permission flags (simplified - would integrate with security context in real implementation)
159
+ status.setCanEdit(canEdit(currentStatus));
160
+ status.setCanSubmit(canSubmit(currentStatus));
161
+ status.setCanApprove(canApprove(currentStatus));
162
+ status.setCanReject(canReject(currentStatus));
163
+ status.setCanPublish(canPublish(currentStatus));
164
+
165
+ return status;
166
+ }
167
+
168
+ /**
169
+ * Create available workflow actions for the draft.
170
+ */
171
+ private List<PolicyDraftOutputDTO.WorkflowActionDTO> createAvailableActions(PolicyDraft draft) {
172
+ List<PolicyDraftOutputDTO.WorkflowActionDTO> actions = new ArrayList<>();
173
+ PolicyDraftStatus status = draft.getStatus();
174
+
175
+ switch (status) {
176
+ case CREATED:
177
+ case REQUIRES_CHANGES:
178
+ actions.add(new PolicyDraftOutputDTO.WorkflowActionDTO("SUBMIT", "Submit for Review"));
179
+ actions.add(new PolicyDraftOutputDTO.WorkflowActionDTO("ARCHIVE", "Archive Draft"));
180
+ break;
181
+ case SUBMITTED:
182
+ case UNDER_REVIEW:
183
+ actions.add(new PolicyDraftOutputDTO.WorkflowActionDTO("APPROVE", "Approve Draft"));
184
+ actions.add(new PolicyDraftOutputDTO.WorkflowActionDTO("REJECT", "Reject Draft"));
185
+ actions.add(new PolicyDraftOutputDTO.WorkflowActionDTO("REQUEST_CHANGES", "Request Changes"));
186
+ break;
187
+ case APPROVED:
188
+ actions.add(new PolicyDraftOutputDTO.WorkflowActionDTO("PUBLISH", "Publish Policy"));
189
+ actions.add(new PolicyDraftOutputDTO.WorkflowActionDTO("REJECT", "Reject Draft"));
190
+ break;
191
+ default:
192
+ // No actions available for REJECTED, PUBLISHED, ARCHIVED
193
+ break;
194
+ }
195
+
196
+ // Set action properties
197
+ for (PolicyDraftOutputDTO.WorkflowActionDTO action : actions) {
198
+ setActionProperties(action);
199
+ }
200
+
201
+ return actions;
202
+ }
203
+
204
+ /**
205
+ * Get human-readable description for status.
206
+ */
207
+ private String getStatusDescription(PolicyDraftStatus status) {
208
+ switch (status) {
209
+ case CREATED:
210
+ return "Draft has been created and is ready for editing";
211
+ case SUBMITTED:
212
+ return "Draft has been submitted and is awaiting review";
213
+ case UNDER_REVIEW:
214
+ return "Draft is currently being reviewed";
215
+ case REQUIRES_CHANGES:
216
+ return "Draft requires changes based on reviewer feedback";
217
+ case APPROVED:
218
+ return "Draft has been approved and is ready for publication";
219
+ case REJECTED:
220
+ return "Draft has been rejected and will not be published";
221
+ case PUBLISHED:
222
+ return "Draft has been published as an active policy";
223
+ case ARCHIVED:
224
+ return "Draft has been archived and is no longer active";
225
+ default:
226
+ return "Unknown status";
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Get next possible states for workflow transitions.
232
+ */
233
+ private List<String> getNextPossibleStates(PolicyDraftStatus status) {
234
+ switch (status) {
235
+ case CREATED:
236
+ case REQUIRES_CHANGES:
237
+ return Arrays.asList("SUBMITTED", "ARCHIVED");
238
+ case SUBMITTED:
239
+ return Arrays.asList("UNDER_REVIEW", "APPROVED", "REJECTED", "REQUIRES_CHANGES");
240
+ case UNDER_REVIEW:
241
+ return Arrays.asList("APPROVED", "REJECTED", "REQUIRES_CHANGES");
242
+ case APPROVED:
243
+ return Arrays.asList("PUBLISHED", "REJECTED");
244
+ default:
245
+ return new ArrayList<>(); // Terminal states
246
+ }
247
+ }
248
+
249
+ /**
250
+ * Get color for UI status indicators.
251
+ */
252
+ private String getStageColor(PolicyDraftStatus status) {
253
+ switch (status) {
254
+ case CREATED:
255
+ return "blue";
256
+ case SUBMITTED:
257
+ case UNDER_REVIEW:
258
+ return "orange";
259
+ case REQUIRES_CHANGES:
260
+ return "yellow";
261
+ case APPROVED:
262
+ return "green";
263
+ case REJECTED:
264
+ return "red";
265
+ case PUBLISHED:
266
+ return "purple";
267
+ case ARCHIVED:
268
+ return "gray";
269
+ default:
270
+ return "gray";
271
+ }
272
+ }
273
+
274
+ /**
275
+ * Get the timestamp of last status change.
276
+ */
277
+ private Instant getLastStatusChangeTime(PolicyDraft draft, PolicyDraftStatus currentStatus) {
278
+ switch (currentStatus) {
279
+ case SUBMITTED:
280
+ return draft.getSubmittedAt();
281
+ case APPROVED:
282
+ return draft.getApprovedAt();
283
+ case REJECTED:
284
+ return draft.getRejectedAt();
285
+ case PUBLISHED:
286
+ return draft.getPublishedAt();
287
+ default:
288
+ return draft.getUpdatedAt();
289
+ }
290
+ }
291
+
292
+ /**
293
+ * Check if draft can be edited in current status.
294
+ */
295
+ private boolean canEdit(PolicyDraftStatus status) {
296
+ return status == PolicyDraftStatus.CREATED || status == PolicyDraftStatus.REQUIRES_CHANGES;
297
+ }
298
+
299
+ /**
300
+ * Check if draft can be submitted in current status.
301
+ */
302
+ private boolean canSubmit(PolicyDraftStatus status) {
303
+ return status == PolicyDraftStatus.CREATED || status == PolicyDraftStatus.REQUIRES_CHANGES;
304
+ }
305
+
306
+ /**
307
+ * Check if draft can be approved in current status.
308
+ */
309
+ private boolean canApprove(PolicyDraftStatus status) {
310
+ return status == PolicyDraftStatus.SUBMITTED || status == PolicyDraftStatus.UNDER_REVIEW;
311
+ }
312
+
313
+ /**
314
+ * Check if draft can be rejected in current status.
315
+ */
316
+ private boolean canReject(PolicyDraftStatus status) {
317
+ return status == PolicyDraftStatus.SUBMITTED ||
318
+ status == PolicyDraftStatus.UNDER_REVIEW ||
319
+ status == PolicyDraftStatus.APPROVED;
320
+ }
321
+
322
+ /**
323
+ * Check if draft can be published in current status.
324
+ */
325
+ private boolean canPublish(PolicyDraftStatus status) {
326
+ return status == PolicyDraftStatus.APPROVED;
327
+ }
328
+
329
+ /**
330
+ * Set properties for workflow actions.
331
+ */
332
+ private void setActionProperties(PolicyDraftOutputDTO.WorkflowActionDTO action) {
333
+ switch (action.getActionType()) {
334
+ case "SUBMIT":
335
+ action.setActionDescription("Submit the draft for review by approvers");
336
+ action.setRequiresComment(false);
337
+ action.setConfirmationMessage("Are you sure you want to submit this draft for review?");
338
+ action.setButtonStyle("primary");
339
+ break;
340
+ case "APPROVE":
341
+ action.setActionDescription("Approve the draft for publication");
342
+ action.setRequiresComment(false);
343
+ action.setConfirmationMessage("Are you sure you want to approve this draft?");
344
+ action.setButtonStyle("success");
345
+ break;
346
+ case "REJECT":
347
+ action.setActionDescription("Reject the draft and prevent publication");
348
+ action.setRequiresComment(true);
349
+ action.setConfirmationMessage("Are you sure you want to reject this draft? This action cannot be undone.");
350
+ action.setButtonStyle("danger");
351
+ break;
352
+ case "REQUEST_CHANGES":
353
+ action.setActionDescription("Request changes from the draft author");
354
+ action.setRequiresComment(true);
355
+ action.setConfirmationMessage("Please provide details about the required changes");
356
+ action.setButtonStyle("warning");
357
+ break;
358
+ case "PUBLISH":
359
+ action.setActionDescription("Publish the draft as an active policy");
360
+ action.setRequiresComment(false);
361
+ action.setConfirmationMessage("Are you sure you want to publish this draft as an active policy?");
362
+ action.setButtonStyle("success");
363
+ break;
364
+ case "ARCHIVE":
365
+ action.setActionDescription("Archive the draft");
366
+ action.setRequiresComment(false);
367
+ action.setConfirmationMessage("Are you sure you want to archive this draft?");
368
+ action.setButtonStyle("secondary");
369
+ break;
370
+ }
371
+ }
372
+ }
src/main/java/com/dalab/policyengine/mapper/PolicyMapper.java ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.mapper;
2
+
3
+ import java.util.Collections;
4
+ import java.util.UUID;
5
+ import java.util.stream.Collectors;
6
+
7
+ import org.springframework.stereotype.Component;
8
+
9
+ import com.dalab.policyengine.dto.PolicyEvaluationOutputDTO;
10
+ import com.dalab.policyengine.dto.PolicyEvaluationSummaryDTO;
11
+ // Add missing DTO imports
12
+ import com.dalab.policyengine.dto.PolicyInputDTO;
13
+ import com.dalab.policyengine.dto.PolicyOutputDTO;
14
+ import com.dalab.policyengine.dto.PolicyRuleDTO;
15
+ import com.dalab.policyengine.dto.PolicySummaryDTO;
16
+ // Add missing entity imports
17
+ import com.dalab.policyengine.model.Policy;
18
+ import com.dalab.policyengine.model.PolicyEvaluation;
19
+ import com.dalab.policyengine.model.PolicyEvaluationStatus;
20
+ import com.dalab.policyengine.model.PolicyRule;
21
+
22
+ @Component
23
+ public class PolicyMapper {
24
+
25
+ public PolicySummaryDTO toPolicySummaryDTO(Policy policy) {
26
+ if (policy == null) return null;
27
+ PolicySummaryDTO dto = new PolicySummaryDTO();
28
+ dto.setId(policy.getId());
29
+ dto.setName(policy.getName());
30
+ dto.setDescription(policy.getDescription());
31
+ dto.setStatus(policy.getStatus());
32
+ dto.setRuleCount(policy.getRules() != null ? policy.getRules().size() : 0);
33
+ dto.setCreatedAt(policy.getCreatedAt());
34
+ dto.setUpdatedAt(policy.getUpdatedAt());
35
+ return dto;
36
+ }
37
+
38
+ public PolicyOutputDTO toPolicyOutputDTO(Policy policy) {
39
+ if (policy == null) return null;
40
+ PolicyOutputDTO dto = new PolicyOutputDTO();
41
+ dto.setId(policy.getId());
42
+ dto.setName(policy.getName());
43
+ dto.setDescription(policy.getDescription());
44
+ dto.setStatus(policy.getStatus());
45
+ dto.setConditionLogic(policy.getConditionLogic());
46
+ dto.setActions(policy.getActions());
47
+ dto.setRules(policy.getRules().stream().map(this::toPolicyRuleDTO).collect(Collectors.toList()));
48
+ dto.setCreatedAt(policy.getCreatedAt());
49
+ dto.setUpdatedAt(policy.getUpdatedAt());
50
+ dto.setCreatedByUserId(policy.getCreatedByUserId());
51
+ dto.setUpdatedByUserId(policy.getUpdatedByUserId());
52
+ return dto;
53
+ }
54
+
55
+ public PolicyRuleDTO toPolicyRuleDTO(PolicyRule policyRule) {
56
+ if (policyRule == null) return null;
57
+ PolicyRuleDTO dto = new PolicyRuleDTO();
58
+ dto.setId(policyRule.getId() != null ? policyRule.getId().toString() : null);
59
+ dto.setName(policyRule.getName());
60
+ dto.setDescription(policyRule.getDescription());
61
+ dto.setCondition(policyRule.getCondition());
62
+ dto.setPriority(policyRule.getPriority());
63
+ dto.setActions(policyRule.getActions());
64
+ return dto;
65
+ }
66
+
67
+ public Policy toPolicyEntity(PolicyInputDTO dto) {
68
+ if (dto == null) return null;
69
+ Policy policy = new Policy();
70
+ updatePolicyEntityFromInputDTO(policy, dto); // Reuse logic for update
71
+ return policy;
72
+ }
73
+
74
+ public void updatePolicyEntityFromInputDTO(Policy policy, PolicyInputDTO dto) {
75
+ if (policy == null || dto == null) return;
76
+
77
+ policy.setName(dto.getName());
78
+ policy.setDescription(dto.getDescription());
79
+ policy.setStatus(dto.getStatus());
80
+ policy.setConditionLogic(dto.getConditionLogic());
81
+ policy.setActions(dto.getActions());
82
+
83
+ // Handle rules update carefully
84
+ if (dto.getRules() != null) {
85
+ // Simple strategy: remove all existing and add new ones based on DTO
86
+ // More sophisticated merging could be done (e.g. based on rule ID or name)
87
+ policy.getRules().clear();
88
+ dto.getRules().forEach(ruleDTO -> policy.addRule(toPolicyRuleEntity(ruleDTO)));
89
+ } else {
90
+ policy.setRules(Collections.emptyList());
91
+ }
92
+ }
93
+
94
+ public PolicyRule toPolicyRuleEntity(PolicyRuleDTO dto) {
95
+ if (dto == null) return null;
96
+ PolicyRule rule = new PolicyRule();
97
+ // ID is not set here for new rules, or could be used to fetch existing if updating
98
+ // For simplicity, if ID is present in DTO, we assume it might be used by service layer
99
+ // to find and update existing rule, but mapper focuses on new entity creation or field mapping.
100
+ if (dto.getId() != null) {
101
+ try {
102
+ rule.setId(UUID.fromString(dto.getId()));
103
+ } catch (IllegalArgumentException e) {
104
+ // Handle invalid UUID string if necessary, or let it be null for new entity
105
+ }
106
+ }
107
+ rule.setName(dto.getName());
108
+ rule.setDescription(dto.getDescription());
109
+ rule.setCondition(dto.getCondition());
110
+ rule.setPriority(dto.getPriority());
111
+ rule.setActions(dto.getActions());
112
+ return rule;
113
+ }
114
+
115
+ public PolicyEvaluationOutputDTO toPolicyEvaluationOutputDTO(PolicyEvaluation evaluation, String policyName) {
116
+ if (evaluation == null) return null;
117
+ PolicyEvaluationOutputDTO dto = new PolicyEvaluationOutputDTO();
118
+ dto.setId(evaluation.getId());
119
+ dto.setPolicyId(evaluation.getPolicyId());
120
+ dto.setPolicyName(policyName); // Policy name fetched separately for convenience
121
+ dto.setTargetAssetId(evaluation.getTargetAssetId());
122
+ dto.setStatus(evaluation.getStatus());
123
+ dto.setEvaluationDetails(evaluation.getEvaluationDetails());
124
+ dto.setTriggeredActions(evaluation.getTriggeredActions());
125
+ dto.setEvaluatedAt(evaluation.getEvaluatedAt());
126
+ dto.setEvaluationTriggeredByUserId(evaluation.getEvaluationTriggeredByUserId());
127
+ return dto;
128
+ }
129
+
130
+ public PolicyEvaluationSummaryDTO toPolicyEvaluationSummaryDTO(PolicyEvaluation evaluation, String policyName) {
131
+ if (evaluation == null) return null;
132
+ PolicyEvaluationSummaryDTO dto = new PolicyEvaluationSummaryDTO();
133
+ dto.setId(evaluation.getId());
134
+ dto.setPolicyId(evaluation.getPolicyId());
135
+ dto.setPolicyName(policyName);
136
+ dto.setTargetAssetId(evaluation.getTargetAssetId());
137
+ dto.setStatus(evaluation.getStatus());
138
+ dto.setEvaluatedAt(evaluation.getEvaluatedAt());
139
+ return dto;
140
+ }
141
+ }
src/main/java/com/dalab/policyengine/model/EventRule.java ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.model;
2
+
3
+ import java.time.Instant;
4
+ import java.util.Map;
5
+ import java.util.UUID;
6
+
7
+ import org.hibernate.annotations.JdbcTypeCode;
8
+ import org.hibernate.type.SqlTypes;
9
+
10
+ import jakarta.persistence.Column;
11
+ import jakarta.persistence.Entity;
12
+ import jakarta.persistence.FetchType;
13
+ import jakarta.persistence.GeneratedValue;
14
+ import jakarta.persistence.GenerationType;
15
+ import jakarta.persistence.Id;
16
+ import jakarta.persistence.JoinColumn;
17
+ import jakarta.persistence.ManyToOne;
18
+ import jakarta.persistence.PrePersist;
19
+ import jakarta.persistence.PreUpdate;
20
+ import jakarta.persistence.Table;
21
+ import jakarta.validation.constraints.NotBlank;
22
+ import jakarta.validation.constraints.Size;
23
+
24
+ /**
25
+ * Entity representing a filtering rule for event subscriptions.
26
+ * Uses MVEL expressions to define conditions for event matching.
27
+ */
28
+ @Entity
29
+ @Table(name = "event_rules")
30
+ public class EventRule {
31
+
32
+ @Id
33
+ @GeneratedValue(strategy = GenerationType.AUTO)
34
+ @Column(columnDefinition = "UUID")
35
+ private UUID id;
36
+
37
+ @NotBlank
38
+ @Size(max = 255)
39
+ @Column(nullable = false)
40
+ private String name;
41
+
42
+ @Size(max = 500)
43
+ private String description;
44
+
45
+ @ManyToOne(fetch = FetchType.LAZY)
46
+ @JoinColumn(name = "subscription_id", nullable = false)
47
+ private EventSubscription subscription;
48
+
49
+ /**
50
+ * MVEL expression for evaluating events
51
+ * Example: "eventType == 'POLICY_VIOLATION' && severity == 'HIGH' && assetId.startsWith('prod-')"
52
+ */
53
+ @Column(columnDefinition = "TEXT", nullable = false)
54
+ private String condition;
55
+
56
+ /**
57
+ * Rule priority (lower number = higher priority)
58
+ */
59
+ @Column(nullable = false)
60
+ private Integer priority = 1;
61
+
62
+ /**
63
+ * Whether this rule is enabled
64
+ */
65
+ @Column(nullable = false)
66
+ private Boolean enabled = true;
67
+
68
+ /**
69
+ * Additional parameters for the rule
70
+ */
71
+ @JdbcTypeCode(SqlTypes.JSON)
72
+ @Column(columnDefinition = "jsonb")
73
+ private Map<String, Object> parameters;
74
+
75
+ @Column(nullable = false, updatable = false)
76
+ private Instant createdAt;
77
+
78
+ private Instant updatedAt;
79
+
80
+ @Column(columnDefinition = "UUID")
81
+ private UUID createdByUserId;
82
+
83
+ @Column(columnDefinition = "UUID")
84
+ private UUID updatedByUserId;
85
+
86
+ // Constructors
87
+ public EventRule() {}
88
+
89
+ public EventRule(String name, String condition) {
90
+ this.name = name;
91
+ this.condition = condition;
92
+ }
93
+
94
+ // Getters and Setters
95
+
96
+ public UUID getId() {
97
+ return id;
98
+ }
99
+
100
+ public void setId(UUID id) {
101
+ this.id = id;
102
+ }
103
+
104
+ public String getName() {
105
+ return name;
106
+ }
107
+
108
+ public void setName(String name) {
109
+ this.name = name;
110
+ }
111
+
112
+ public String getDescription() {
113
+ return description;
114
+ }
115
+
116
+ public void setDescription(String description) {
117
+ this.description = description;
118
+ }
119
+
120
+ public EventSubscription getSubscription() {
121
+ return subscription;
122
+ }
123
+
124
+ public void setSubscription(EventSubscription subscription) {
125
+ this.subscription = subscription;
126
+ }
127
+
128
+ public String getCondition() {
129
+ return condition;
130
+ }
131
+
132
+ public void setCondition(String condition) {
133
+ this.condition = condition;
134
+ }
135
+
136
+ public Integer getPriority() {
137
+ return priority;
138
+ }
139
+
140
+ public void setPriority(Integer priority) {
141
+ this.priority = priority;
142
+ }
143
+
144
+ public Boolean getEnabled() {
145
+ return enabled;
146
+ }
147
+
148
+ public void setEnabled(Boolean enabled) {
149
+ this.enabled = enabled;
150
+ }
151
+
152
+ public Map<String, Object> getParameters() {
153
+ return parameters;
154
+ }
155
+
156
+ public void setParameters(Map<String, Object> parameters) {
157
+ this.parameters = parameters;
158
+ }
159
+
160
+ public Instant getCreatedAt() {
161
+ return createdAt;
162
+ }
163
+
164
+ public void setCreatedAt(Instant createdAt) {
165
+ this.createdAt = createdAt;
166
+ }
167
+
168
+ public Instant getUpdatedAt() {
169
+ return updatedAt;
170
+ }
171
+
172
+ public void setUpdatedAt(Instant updatedAt) {
173
+ this.updatedAt = updatedAt;
174
+ }
175
+
176
+ public UUID getCreatedByUserId() {
177
+ return createdByUserId;
178
+ }
179
+
180
+ public void setCreatedByUserId(UUID createdByUserId) {
181
+ this.createdByUserId = createdByUserId;
182
+ }
183
+
184
+ public UUID getUpdatedByUserId() {
185
+ return updatedByUserId;
186
+ }
187
+
188
+ public void setUpdatedByUserId(UUID updatedByUserId) {
189
+ this.updatedByUserId = updatedByUserId;
190
+ }
191
+
192
+ @PrePersist
193
+ protected void onCreate() {
194
+ createdAt = Instant.now();
195
+ updatedAt = Instant.now();
196
+ }
197
+
198
+ @PreUpdate
199
+ protected void onUpdate() {
200
+ updatedAt = Instant.now();
201
+ }
202
+
203
+ @Override
204
+ public boolean equals(Object o) {
205
+ if (this == o) return true;
206
+ if (!(o instanceof EventRule)) return false;
207
+ EventRule eventRule = (EventRule) o;
208
+ return id != null && id.equals(eventRule.getId());
209
+ }
210
+
211
+ @Override
212
+ public int hashCode() {
213
+ return getClass().hashCode();
214
+ }
215
+
216
+ @Override
217
+ public String toString() {
218
+ return "EventRule{" +
219
+ "id=" + id +
220
+ ", name='" + name + '\'' +
221
+ ", condition='" + condition + '\'' +
222
+ ", priority=" + priority +
223
+ ", enabled=" + enabled +
224
+ '}';
225
+ }
226
+ }
src/main/java/com/dalab/policyengine/model/EventSeverity.java ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.model;
2
+
3
+ /**
4
+ * Enumeration representing the severity levels of events in the DALab platform.
5
+ */
6
+ public enum EventSeverity {
7
+ /**
8
+ * Critical severity - immediate attention required
9
+ */
10
+ CRITICAL,
11
+
12
+ /**
13
+ * High severity - urgent attention required
14
+ */
15
+ HIGH,
16
+
17
+ /**
18
+ * Medium severity - attention required
19
+ */
20
+ MEDIUM,
21
+
22
+ /**
23
+ * Low severity - informational
24
+ */
25
+ LOW,
26
+
27
+ /**
28
+ * Informational - for logging and tracking purposes
29
+ */
30
+ INFO
31
+ }
src/main/java/com/dalab/policyengine/model/EventSubscription.java ADDED
@@ -0,0 +1,339 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.model;
2
+
3
+ import java.time.Instant;
4
+ import java.util.ArrayList;
5
+ import java.util.List;
6
+ import java.util.Map;
7
+ import java.util.UUID;
8
+
9
+ import org.hibernate.annotations.JdbcTypeCode;
10
+ import org.hibernate.type.SqlTypes;
11
+
12
+ import jakarta.persistence.CascadeType;
13
+ import jakarta.persistence.CollectionTable;
14
+ import jakarta.persistence.Column;
15
+ import jakarta.persistence.ElementCollection;
16
+ import jakarta.persistence.Entity;
17
+ import jakarta.persistence.EnumType;
18
+ import jakarta.persistence.Enumerated;
19
+ import jakarta.persistence.FetchType;
20
+ import jakarta.persistence.GeneratedValue;
21
+ import jakarta.persistence.GenerationType;
22
+ import jakarta.persistence.Id;
23
+ import jakarta.persistence.JoinColumn;
24
+ import jakarta.persistence.OneToMany;
25
+ import jakarta.persistence.PrePersist;
26
+ import jakarta.persistence.PreUpdate;
27
+ import jakarta.persistence.Table;
28
+ import jakarta.validation.constraints.NotBlank;
29
+ import jakarta.validation.constraints.NotNull;
30
+ import jakarta.validation.constraints.Size;
31
+
32
+ /**
33
+ * Entity representing an event subscription configuration.
34
+ * Users can subscribe to specific types of events and configure
35
+ * notification preferences and action triggers.
36
+ */
37
+ @Entity
38
+ @Table(name = "event_subscriptions")
39
+ public class EventSubscription {
40
+
41
+ @Id
42
+ @GeneratedValue(strategy = GenerationType.AUTO)
43
+ @Column(columnDefinition = "UUID")
44
+ private UUID id;
45
+
46
+ @NotBlank
47
+ @Size(max = 255)
48
+ @Column(nullable = false)
49
+ private String name;
50
+
51
+ @Size(max = 1000)
52
+ private String description;
53
+
54
+ @NotNull
55
+ @Column(columnDefinition = "UUID", nullable = false)
56
+ private UUID userId;
57
+
58
+ @Enumerated(EnumType.STRING)
59
+ @Column(nullable = false)
60
+ private EventSubscriptionStatus status = EventSubscriptionStatus.ACTIVE;
61
+
62
+ /**
63
+ * Event types to subscribe to (e.g., POLICY_VIOLATION, ASSET_DISCOVERED, COMPLIANCE_ISSUE)
64
+ */
65
+ @ElementCollection(fetch = FetchType.EAGER)
66
+ @CollectionTable(name = "event_subscription_types", joinColumns = @JoinColumn(name = "subscription_id"))
67
+ @Enumerated(EnumType.STRING)
68
+ @Column(name = "event_type")
69
+ private List<EventType> eventTypes = new ArrayList<>();
70
+
71
+ /**
72
+ * Event severity levels to include (e.g., HIGH, MEDIUM, LOW)
73
+ */
74
+ @ElementCollection(fetch = FetchType.EAGER)
75
+ @CollectionTable(name = "event_subscription_severities", joinColumns = @JoinColumn(name = "subscription_id"))
76
+ @Enumerated(EnumType.STRING)
77
+ @Column(name = "severity")
78
+ private List<EventSeverity> severities = new ArrayList<>();
79
+
80
+ /**
81
+ * Source services to monitor (e.g., da-catalog, da-discovery, da-compliance)
82
+ */
83
+ @ElementCollection(fetch = FetchType.EAGER)
84
+ @CollectionTable(name = "event_subscription_sources", joinColumns = @JoinColumn(name = "subscription_id"))
85
+ @Column(name = "source_service")
86
+ private List<String> sourceServices = new ArrayList<>();
87
+
88
+ /**
89
+ * Filter conditions for events (MVEL expressions)
90
+ */
91
+ @OneToMany(mappedBy = "subscription", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
92
+ private List<EventRule> rules = new ArrayList<>();
93
+
94
+ /**
95
+ * Notification preferences and action configurations
96
+ */
97
+ @JdbcTypeCode(SqlTypes.JSON)
98
+ @Column(columnDefinition = "jsonb")
99
+ private Map<String, Object> notificationConfig; // e.g., { "email": true, "slack": { "channel": "#alerts" } }
100
+
101
+ /**
102
+ * Action configurations to trigger when events match
103
+ */
104
+ @JdbcTypeCode(SqlTypes.JSON)
105
+ @Column(columnDefinition = "jsonb")
106
+ private Map<String, Object> actionConfig; // e.g., { "autoQuarantine": true, "escalateTo": "admin" }
107
+
108
+ @Column(nullable = false, updatable = false)
109
+ private Instant createdAt;
110
+
111
+ private Instant updatedAt;
112
+
113
+ @Column(columnDefinition = "UUID")
114
+ private UUID createdByUserId;
115
+
116
+ @Column(columnDefinition = "UUID")
117
+ private UUID updatedByUserId;
118
+
119
+ // Constructors
120
+ public EventSubscription() {}
121
+
122
+ public EventSubscription(String name, UUID userId) {
123
+ this.name = name;
124
+ this.userId = userId;
125
+ }
126
+
127
+ // Getters and Setters
128
+
129
+ public UUID getId() {
130
+ return id;
131
+ }
132
+
133
+ public void setId(UUID id) {
134
+ this.id = id;
135
+ }
136
+
137
+ public String getName() {
138
+ return name;
139
+ }
140
+
141
+ public void setName(String name) {
142
+ this.name = name;
143
+ }
144
+
145
+ public String getDescription() {
146
+ return description;
147
+ }
148
+
149
+ public void setDescription(String description) {
150
+ this.description = description;
151
+ }
152
+
153
+ public UUID getUserId() {
154
+ return userId;
155
+ }
156
+
157
+ public void setUserId(UUID userId) {
158
+ this.userId = userId;
159
+ }
160
+
161
+ public EventSubscriptionStatus getStatus() {
162
+ return status;
163
+ }
164
+
165
+ public void setStatus(EventSubscriptionStatus status) {
166
+ this.status = status;
167
+ }
168
+
169
+ public List<EventType> getEventTypes() {
170
+ return eventTypes;
171
+ }
172
+
173
+ public void setEventTypes(List<EventType> eventTypes) {
174
+ this.eventTypes = eventTypes != null ? eventTypes : new ArrayList<>();
175
+ }
176
+
177
+ public void addEventType(EventType eventType) {
178
+ if (this.eventTypes == null) {
179
+ this.eventTypes = new ArrayList<>();
180
+ }
181
+ this.eventTypes.add(eventType);
182
+ }
183
+
184
+ public void removeEventType(EventType eventType) {
185
+ if (this.eventTypes != null) {
186
+ this.eventTypes.remove(eventType);
187
+ }
188
+ }
189
+
190
+ public List<EventSeverity> getSeverities() {
191
+ return severities;
192
+ }
193
+
194
+ public void setSeverities(List<EventSeverity> severities) {
195
+ this.severities = severities != null ? severities : new ArrayList<>();
196
+ }
197
+
198
+ public void addSeverity(EventSeverity severity) {
199
+ if (this.severities == null) {
200
+ this.severities = new ArrayList<>();
201
+ }
202
+ this.severities.add(severity);
203
+ }
204
+
205
+ public void removeSeverity(EventSeverity severity) {
206
+ if (this.severities != null) {
207
+ this.severities.remove(severity);
208
+ }
209
+ }
210
+
211
+ public List<String> getSourceServices() {
212
+ return sourceServices;
213
+ }
214
+
215
+ public void setSourceServices(List<String> sourceServices) {
216
+ this.sourceServices = sourceServices != null ? sourceServices : new ArrayList<>();
217
+ }
218
+
219
+ public void addSourceService(String sourceService) {
220
+ if (this.sourceServices == null) {
221
+ this.sourceServices = new ArrayList<>();
222
+ }
223
+ this.sourceServices.add(sourceService);
224
+ }
225
+
226
+ public void removeSourceService(String sourceService) {
227
+ if (this.sourceServices != null) {
228
+ this.sourceServices.remove(sourceService);
229
+ }
230
+ }
231
+
232
+ public List<EventRule> getRules() {
233
+ return rules;
234
+ }
235
+
236
+ public void setRules(List<EventRule> rules) {
237
+ this.rules = rules != null ? rules : new ArrayList<>();
238
+ this.rules.forEach(rule -> rule.setSubscription(this));
239
+ }
240
+
241
+ public void addRule(EventRule rule) {
242
+ if (this.rules == null) {
243
+ this.rules = new ArrayList<>();
244
+ }
245
+ this.rules.add(rule);
246
+ rule.setSubscription(this);
247
+ }
248
+
249
+ public void removeRule(EventRule rule) {
250
+ if (this.rules != null) {
251
+ this.rules.remove(rule);
252
+ rule.setSubscription(null);
253
+ }
254
+ }
255
+
256
+ public Map<String, Object> getNotificationConfig() {
257
+ return notificationConfig;
258
+ }
259
+
260
+ public void setNotificationConfig(Map<String, Object> notificationConfig) {
261
+ this.notificationConfig = notificationConfig;
262
+ }
263
+
264
+ public Map<String, Object> getActionConfig() {
265
+ return actionConfig;
266
+ }
267
+
268
+ public void setActionConfig(Map<String, Object> actionConfig) {
269
+ this.actionConfig = actionConfig;
270
+ }
271
+
272
+ public Instant getCreatedAt() {
273
+ return createdAt;
274
+ }
275
+
276
+ public void setCreatedAt(Instant createdAt) {
277
+ this.createdAt = createdAt;
278
+ }
279
+
280
+ public Instant getUpdatedAt() {
281
+ return updatedAt;
282
+ }
283
+
284
+ public void setUpdatedAt(Instant updatedAt) {
285
+ this.updatedAt = updatedAt;
286
+ }
287
+
288
+ public UUID getCreatedByUserId() {
289
+ return createdByUserId;
290
+ }
291
+
292
+ public void setCreatedByUserId(UUID createdByUserId) {
293
+ this.createdByUserId = createdByUserId;
294
+ }
295
+
296
+ public UUID getUpdatedByUserId() {
297
+ return updatedByUserId;
298
+ }
299
+
300
+ public void setUpdatedByUserId(UUID updatedByUserId) {
301
+ this.updatedByUserId = updatedByUserId;
302
+ }
303
+
304
+ @PrePersist
305
+ protected void onCreate() {
306
+ createdAt = Instant.now();
307
+ updatedAt = Instant.now();
308
+ }
309
+
310
+ @PreUpdate
311
+ protected void onUpdate() {
312
+ updatedAt = Instant.now();
313
+ }
314
+
315
+ @Override
316
+ public boolean equals(Object o) {
317
+ if (this == o) return true;
318
+ if (!(o instanceof EventSubscription)) return false;
319
+ EventSubscription that = (EventSubscription) o;
320
+ return id != null && id.equals(that.getId());
321
+ }
322
+
323
+ @Override
324
+ public int hashCode() {
325
+ return getClass().hashCode();
326
+ }
327
+
328
+ @Override
329
+ public String toString() {
330
+ return "EventSubscription{" +
331
+ "id=" + id +
332
+ ", name='" + name + '\'' +
333
+ ", userId=" + userId +
334
+ ", status=" + status +
335
+ ", eventTypes=" + eventTypes +
336
+ ", severities=" + severities +
337
+ '}';
338
+ }
339
+ }
src/main/java/com/dalab/policyengine/model/EventSubscriptionStatus.java ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.model;
2
+
3
+ /**
4
+ * Enumeration representing the status of an event subscription.
5
+ */
6
+ public enum EventSubscriptionStatus {
7
+ /**
8
+ * Subscription is active and receiving events
9
+ */
10
+ ACTIVE,
11
+
12
+ /**
13
+ * Subscription is temporarily paused
14
+ */
15
+ PAUSED,
16
+
17
+ /**
18
+ * Subscription is disabled and not receiving events
19
+ */
20
+ DISABLED,
21
+
22
+ /**
23
+ * Subscription has been archived
24
+ */
25
+ ARCHIVED
26
+ }
src/main/java/com/dalab/policyengine/model/EventType.java ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.model;
2
+
3
+ /**
4
+ * Enumeration representing different types of events that can occur in the DALab platform.
5
+ */
6
+ public enum EventType {
7
+ // Policy-related events
8
+ /**
9
+ * Policy violation detected
10
+ */
11
+ POLICY_VIOLATION,
12
+
13
+ /**
14
+ * Policy evaluation completed
15
+ */
16
+ POLICY_EVALUATION_COMPLETED,
17
+
18
+ /**
19
+ * Policy applied to assets
20
+ */
21
+ POLICY_APPLIED,
22
+
23
+ /**
24
+ * Policy rule triggered
25
+ */
26
+ POLICY_RULE_TRIGGERED,
27
+
28
+ // Asset-related events
29
+ /**
30
+ * New asset discovered
31
+ */
32
+ ASSET_DISCOVERED,
33
+
34
+ /**
35
+ * Asset metadata changed
36
+ */
37
+ ASSET_METADATA_CHANGED,
38
+
39
+ /**
40
+ * Asset classification changed
41
+ */
42
+ ASSET_CLASSIFICATION_CHANGED,
43
+
44
+ /**
45
+ * Asset access pattern detected
46
+ */
47
+ ASSET_ACCESS_DETECTED,
48
+
49
+ // Compliance-related events
50
+ /**
51
+ * Compliance violation detected
52
+ */
53
+ COMPLIANCE_VIOLATION,
54
+
55
+ /**
56
+ * Compliance scan completed
57
+ */
58
+ COMPLIANCE_SCAN_COMPLETED,
59
+
60
+ /**
61
+ * Regulatory requirement changed
62
+ */
63
+ REGULATORY_CHANGE,
64
+
65
+ // Data lifecycle events
66
+ /**
67
+ * Asset scheduled for archival
68
+ */
69
+ ASSET_ARCHIVAL_SCHEDULED,
70
+
71
+ /**
72
+ * Asset archival completed
73
+ */
74
+ ASSET_ARCHIVAL_COMPLETED,
75
+
76
+ /**
77
+ * Asset deletion scheduled
78
+ */
79
+ ASSET_DELETION_SCHEDULED,
80
+
81
+ /**
82
+ * Asset deletion completed
83
+ */
84
+ ASSET_DELETION_COMPLETED,
85
+
86
+ // System events
87
+ /**
88
+ * System alert generated
89
+ */
90
+ SYSTEM_ALERT,
91
+
92
+ /**
93
+ * Service health check failed
94
+ */
95
+ SERVICE_HEALTH_ISSUE,
96
+
97
+ /**
98
+ * Data quality issue detected
99
+ */
100
+ DATA_QUALITY_ISSUE,
101
+
102
+ /**
103
+ * Security incident detected
104
+ */
105
+ SECURITY_INCIDENT,
106
+
107
+ // User activity events
108
+ /**
109
+ * User access pattern anomaly
110
+ */
111
+ USER_ACCESS_ANOMALY,
112
+
113
+ /**
114
+ * Unauthorized access attempt
115
+ */
116
+ UNAUTHORIZED_ACCESS_ATTEMPT,
117
+
118
+ // Generic event type for custom events
119
+ /**
120
+ * Custom event type
121
+ */
122
+ CUSTOM_EVENT
123
+ }
src/main/java/com/dalab/policyengine/model/Policy.java ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.model;
2
+
3
+ import java.time.Instant;
4
+ import java.util.ArrayList;
5
+ import java.util.List;
6
+ import java.util.Map;
7
+ import java.util.UUID;
8
+
9
+ import org.hibernate.annotations.JdbcTypeCode;
10
+ import org.hibernate.type.SqlTypes;
11
+
12
+ import jakarta.persistence.*;
13
+ import jakarta.validation.constraints.NotBlank;
14
+ import jakarta.validation.constraints.Size;
15
+
16
+ @Entity
17
+ @Table(name = "policies")
18
+ public class Policy {
19
+
20
+ @Id
21
+ @GeneratedValue(strategy = GenerationType.AUTO)
22
+ @Column(columnDefinition = "UUID")
23
+ private UUID id;
24
+
25
+ @NotBlank
26
+ @Size(max = 255)
27
+ @Column(nullable = false, unique = true)
28
+ private String name;
29
+
30
+ @Size(max = 1000)
31
+ private String description;
32
+
33
+ @Enumerated(EnumType.STRING)
34
+ @Column(nullable = false)
35
+ private PolicyStatus status = PolicyStatus.DISABLED;
36
+
37
+ // MVEL condition for the policy. If all rules pass, this condition is evaluated.
38
+ // Could be null if policy relies solely on its individual rules.
39
+ @Column(columnDefinition = "TEXT")
40
+ private String conditionLogic; // e.g., "rule1 && (rule2 || rule3)"
41
+
42
+ @OneToMany(mappedBy = "policy", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
43
+ private List<PolicyRule> rules = new ArrayList<>();
44
+
45
+ @JdbcTypeCode(SqlTypes.JSON)
46
+ @Column(columnDefinition = "jsonb")
47
+ private Map<String, Object> actions; // e.g., { "notify": { "email": "admin@example.com" }, "addLabel": "Sensitive" }
48
+
49
+ @Column(nullable = false, updatable = false)
50
+ private Instant createdAt;
51
+
52
+ private Instant updatedAt;
53
+
54
+ @Column(columnDefinition = "UUID")
55
+ private UUID createdByUserId;
56
+
57
+ @Column(columnDefinition = "UUID")
58
+ private UUID updatedByUserId;
59
+
60
+ // Getters and Setters
61
+
62
+ public UUID getId() {
63
+ return id;
64
+ }
65
+
66
+ public void setId(UUID id) {
67
+ this.id = id;
68
+ }
69
+
70
+ public String getName() {
71
+ return name;
72
+ }
73
+
74
+ public void setName(String name) {
75
+ this.name = name;
76
+ }
77
+
78
+ public String getDescription() {
79
+ return description;
80
+ }
81
+
82
+ public void setDescription(String description) {
83
+ this.description = description;
84
+ }
85
+
86
+ public PolicyStatus getStatus() {
87
+ return status;
88
+ }
89
+
90
+ public void setStatus(PolicyStatus status) {
91
+ this.status = status;
92
+ }
93
+
94
+ public String getConditionLogic() {
95
+ return conditionLogic;
96
+ }
97
+
98
+ public void setConditionLogic(String conditionLogic) {
99
+ this.conditionLogic = conditionLogic;
100
+ }
101
+
102
+ public List<PolicyRule> getRules() {
103
+ return rules;
104
+ }
105
+
106
+ public void setRules(List<PolicyRule> rules) {
107
+ this.rules = rules;
108
+ this.rules.forEach(rule -> rule.setPolicy(this));
109
+ }
110
+
111
+ public void addRule(PolicyRule rule) {
112
+ this.rules.add(rule);
113
+ rule.setPolicy(this);
114
+ }
115
+
116
+ public void removeRule(PolicyRule rule) {
117
+ this.rules.remove(rule);
118
+ rule.setPolicy(null);
119
+ }
120
+
121
+ public Map<String, Object> getActions() {
122
+ return actions;
123
+ }
124
+
125
+ public void setActions(Map<String, Object> actions) {
126
+ this.actions = actions;
127
+ }
128
+
129
+ public Instant getCreatedAt() {
130
+ return createdAt;
131
+ }
132
+
133
+ public void setCreatedAt(Instant createdAt) {
134
+ this.createdAt = createdAt;
135
+ }
136
+
137
+ public Instant getUpdatedAt() {
138
+ return updatedAt;
139
+ }
140
+
141
+ public void setUpdatedAt(Instant updatedAt) {
142
+ this.updatedAt = updatedAt;
143
+ }
144
+
145
+ public UUID getCreatedByUserId() {
146
+ return createdByUserId;
147
+ }
148
+
149
+ public void setCreatedByUserId(UUID createdByUserId) {
150
+ this.createdByUserId = createdByUserId;
151
+ }
152
+
153
+ public UUID getUpdatedByUserId() {
154
+ return updatedByUserId;
155
+ }
156
+
157
+ public void setUpdatedByUserId(UUID updatedByUserId) {
158
+ this.updatedByUserId = updatedByUserId;
159
+ }
160
+
161
+ @PrePersist
162
+ protected void onCreate() {
163
+ createdAt = Instant.now();
164
+ updatedAt = Instant.now();
165
+ }
166
+
167
+ @PreUpdate
168
+ protected void onUpdate() {
169
+ updatedAt = Instant.now();
170
+ }
171
+ }
src/main/java/com/dalab/policyengine/model/PolicyDraft.java ADDED
@@ -0,0 +1,495 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.model;
2
+
3
+ import java.time.Instant;
4
+ import java.util.ArrayList;
5
+ import java.util.List;
6
+ import java.util.Map;
7
+ import java.util.UUID;
8
+
9
+ import org.hibernate.annotations.JdbcTypeCode;
10
+ import org.hibernate.type.SqlTypes;
11
+
12
+ import jakarta.persistence.CollectionTable;
13
+ import jakarta.persistence.Column;
14
+ import jakarta.persistence.ElementCollection;
15
+ import jakarta.persistence.Entity;
16
+ import jakarta.persistence.EnumType;
17
+ import jakarta.persistence.Enumerated;
18
+ import jakarta.persistence.GeneratedValue;
19
+ import jakarta.persistence.GenerationType;
20
+ import jakarta.persistence.Id;
21
+ import jakarta.persistence.JoinColumn;
22
+ import jakarta.persistence.PrePersist;
23
+ import jakarta.persistence.PreUpdate;
24
+ import jakarta.persistence.Table;
25
+ import jakarta.validation.constraints.NotBlank;
26
+ import jakarta.validation.constraints.Size;
27
+
28
+ /**
29
+ * Entity representing a policy draft that goes through approval workflow.
30
+ * Supports versioning, collaboration, and audit trails.
31
+ */
32
+ @Entity
33
+ @Table(name = "policy_drafts")
34
+ public class PolicyDraft {
35
+
36
+ @Id
37
+ @GeneratedValue(strategy = GenerationType.AUTO)
38
+ @Column(columnDefinition = "UUID")
39
+ private UUID id;
40
+
41
+ /**
42
+ * Name of the policy (must be unique when published).
43
+ */
44
+ @NotBlank
45
+ @Size(max = 255)
46
+ @Column(nullable = false)
47
+ private String name;
48
+
49
+ /**
50
+ * Detailed description of the policy's purpose and scope.
51
+ */
52
+ @Size(max = 2000)
53
+ @Column(columnDefinition = "TEXT")
54
+ private String description;
55
+
56
+ /**
57
+ * Current status in the approval workflow.
58
+ */
59
+ @Enumerated(EnumType.STRING)
60
+ @Column(nullable = false)
61
+ private PolicyDraftStatus status = PolicyDraftStatus.CREATED;
62
+
63
+ /**
64
+ * Version number for this draft (incremented on each revision).
65
+ */
66
+ @Column(nullable = false)
67
+ private Integer version = 1;
68
+
69
+ /**
70
+ * Reference to the published policy (if this is an update to existing policy).
71
+ */
72
+ @Column(columnDefinition = "UUID")
73
+ private UUID basePolicyId;
74
+
75
+ /**
76
+ * MVEL condition logic for the policy evaluation.
77
+ */
78
+ @Column(columnDefinition = "TEXT")
79
+ private String conditionLogic;
80
+
81
+ /**
82
+ * JSON representation of policy rules structure.
83
+ * Stored as JSON to support complex rule configurations.
84
+ */
85
+ @JdbcTypeCode(SqlTypes.JSON)
86
+ @Column(columnDefinition = "jsonb")
87
+ private List<Map<String, Object>> rulesDefinition;
88
+
89
+ /**
90
+ * JSON representation of actions to be taken when policy is triggered.
91
+ */
92
+ @JdbcTypeCode(SqlTypes.JSON)
93
+ @Column(columnDefinition = "jsonb")
94
+ private Map<String, Object> actions;
95
+
96
+ /**
97
+ * Change summary describing what was modified in this version.
98
+ */
99
+ @Size(max = 1000)
100
+ @Column(columnDefinition = "TEXT")
101
+ private String changeSummary;
102
+
103
+ /**
104
+ * Justification for the policy changes or creation.
105
+ */
106
+ @Size(max = 2000)
107
+ @Column(columnDefinition = "TEXT")
108
+ private String justification;
109
+
110
+ /**
111
+ * Expected impact of implementing this policy.
112
+ */
113
+ @Size(max = 1000)
114
+ @Column(columnDefinition = "TEXT")
115
+ private String expectedImpact;
116
+
117
+ /**
118
+ * Target implementation date for the policy.
119
+ */
120
+ private Instant targetImplementationDate;
121
+
122
+ /**
123
+ * Priority level for policy implementation (HIGH, MEDIUM, LOW).
124
+ */
125
+ @Size(max = 50)
126
+ private String priority = "MEDIUM";
127
+
128
+ /**
129
+ * Business category or domain this policy applies to.
130
+ */
131
+ @Size(max = 100)
132
+ private String category;
133
+
134
+ /**
135
+ * Tags for categorization and searchability.
136
+ */
137
+ @ElementCollection
138
+ @CollectionTable(name = "policy_draft_tags", joinColumns = @JoinColumn(name = "draft_id"))
139
+ @Column(name = "tag")
140
+ private List<String> tags = new ArrayList<>();
141
+
142
+ /**
143
+ * Stakeholders who should be notified about this policy.
144
+ */
145
+ @ElementCollection
146
+ @CollectionTable(name = "policy_draft_stakeholders", joinColumns = @JoinColumn(name = "draft_id"))
147
+ @Column(name = "stakeholder_id", columnDefinition = "UUID")
148
+ private List<UUID> stakeholders = new ArrayList<>();
149
+
150
+ /**
151
+ * Approval workflow metadata.
152
+ */
153
+ @JdbcTypeCode(SqlTypes.JSON)
154
+ @Column(columnDefinition = "jsonb")
155
+ private Map<String, Object> approvalMetadata;
156
+
157
+ /**
158
+ * Reviewer comments and feedback.
159
+ */
160
+ @JdbcTypeCode(SqlTypes.JSON)
161
+ @Column(columnDefinition = "jsonb")
162
+ private List<Map<String, Object>> reviewComments = new ArrayList<>();
163
+
164
+ // Audit fields
165
+ @Column(nullable = false, updatable = false)
166
+ private Instant createdAt;
167
+
168
+ private Instant updatedAt;
169
+
170
+ @Column(columnDefinition = "UUID", nullable = false)
171
+ private UUID createdByUserId;
172
+
173
+ @Column(columnDefinition = "UUID")
174
+ private UUID updatedByUserId;
175
+
176
+ private Instant submittedAt;
177
+
178
+ @Column(columnDefinition = "UUID")
179
+ private UUID submittedByUserId;
180
+
181
+ private Instant approvedAt;
182
+
183
+ @Column(columnDefinition = "UUID")
184
+ private UUID approvedByUserId;
185
+
186
+ private Instant rejectedAt;
187
+
188
+ @Column(columnDefinition = "UUID")
189
+ private UUID rejectedByUserId;
190
+
191
+ private Instant publishedAt;
192
+
193
+ @Column(columnDefinition = "UUID")
194
+ private UUID publishedByUserId;
195
+
196
+ // Constructors
197
+ public PolicyDraft() {}
198
+
199
+ public PolicyDraft(String name, String description, UUID createdByUserId) {
200
+ this.name = name;
201
+ this.description = description;
202
+ this.createdByUserId = createdByUserId;
203
+ }
204
+
205
+ // Getters and Setters
206
+ public UUID getId() {
207
+ return id;
208
+ }
209
+
210
+ public void setId(UUID id) {
211
+ this.id = id;
212
+ }
213
+
214
+ public String getName() {
215
+ return name;
216
+ }
217
+
218
+ public void setName(String name) {
219
+ this.name = name;
220
+ }
221
+
222
+ public String getDescription() {
223
+ return description;
224
+ }
225
+
226
+ public void setDescription(String description) {
227
+ this.description = description;
228
+ }
229
+
230
+ public PolicyDraftStatus getStatus() {
231
+ return status;
232
+ }
233
+
234
+ public void setStatus(PolicyDraftStatus status) {
235
+ this.status = status;
236
+ }
237
+
238
+ public Integer getVersion() {
239
+ return version;
240
+ }
241
+
242
+ public void setVersion(Integer version) {
243
+ this.version = version;
244
+ }
245
+
246
+ public UUID getBasePolicyId() {
247
+ return basePolicyId;
248
+ }
249
+
250
+ public void setBasePolicyId(UUID basePolicyId) {
251
+ this.basePolicyId = basePolicyId;
252
+ }
253
+
254
+ public String getConditionLogic() {
255
+ return conditionLogic;
256
+ }
257
+
258
+ public void setConditionLogic(String conditionLogic) {
259
+ this.conditionLogic = conditionLogic;
260
+ }
261
+
262
+ public List<Map<String, Object>> getRulesDefinition() {
263
+ return rulesDefinition;
264
+ }
265
+
266
+ public void setRulesDefinition(List<Map<String, Object>> rulesDefinition) {
267
+ this.rulesDefinition = rulesDefinition;
268
+ }
269
+
270
+ public Map<String, Object> getActions() {
271
+ return actions;
272
+ }
273
+
274
+ public void setActions(Map<String, Object> actions) {
275
+ this.actions = actions;
276
+ }
277
+
278
+ public String getChangeSummary() {
279
+ return changeSummary;
280
+ }
281
+
282
+ public void setChangeSummary(String changeSummary) {
283
+ this.changeSummary = changeSummary;
284
+ }
285
+
286
+ public String getJustification() {
287
+ return justification;
288
+ }
289
+
290
+ public void setJustification(String justification) {
291
+ this.justification = justification;
292
+ }
293
+
294
+ public String getExpectedImpact() {
295
+ return expectedImpact;
296
+ }
297
+
298
+ public void setExpectedImpact(String expectedImpact) {
299
+ this.expectedImpact = expectedImpact;
300
+ }
301
+
302
+ public Instant getTargetImplementationDate() {
303
+ return targetImplementationDate;
304
+ }
305
+
306
+ public void setTargetImplementationDate(Instant targetImplementationDate) {
307
+ this.targetImplementationDate = targetImplementationDate;
308
+ }
309
+
310
+ public String getPriority() {
311
+ return priority;
312
+ }
313
+
314
+ public void setPriority(String priority) {
315
+ this.priority = priority;
316
+ }
317
+
318
+ public String getCategory() {
319
+ return category;
320
+ }
321
+
322
+ public void setCategory(String category) {
323
+ this.category = category;
324
+ }
325
+
326
+ public List<String> getTags() {
327
+ return tags;
328
+ }
329
+
330
+ public void setTags(List<String> tags) {
331
+ this.tags = tags;
332
+ }
333
+
334
+ public List<UUID> getStakeholders() {
335
+ return stakeholders;
336
+ }
337
+
338
+ public void setStakeholders(List<UUID> stakeholders) {
339
+ this.stakeholders = stakeholders;
340
+ }
341
+
342
+ public Map<String, Object> getApprovalMetadata() {
343
+ return approvalMetadata;
344
+ }
345
+
346
+ public void setApprovalMetadata(Map<String, Object> approvalMetadata) {
347
+ this.approvalMetadata = approvalMetadata;
348
+ }
349
+
350
+ public List<Map<String, Object>> getReviewComments() {
351
+ return reviewComments;
352
+ }
353
+
354
+ public void setReviewComments(List<Map<String, Object>> reviewComments) {
355
+ this.reviewComments = reviewComments;
356
+ }
357
+
358
+ public Instant getCreatedAt() {
359
+ return createdAt;
360
+ }
361
+
362
+ public void setCreatedAt(Instant createdAt) {
363
+ this.createdAt = createdAt;
364
+ }
365
+
366
+ public Instant getUpdatedAt() {
367
+ return updatedAt;
368
+ }
369
+
370
+ public void setUpdatedAt(Instant updatedAt) {
371
+ this.updatedAt = updatedAt;
372
+ }
373
+
374
+ public UUID getCreatedByUserId() {
375
+ return createdByUserId;
376
+ }
377
+
378
+ public void setCreatedByUserId(UUID createdByUserId) {
379
+ this.createdByUserId = createdByUserId;
380
+ }
381
+
382
+ public UUID getUpdatedByUserId() {
383
+ return updatedByUserId;
384
+ }
385
+
386
+ public void setUpdatedByUserId(UUID updatedByUserId) {
387
+ this.updatedByUserId = updatedByUserId;
388
+ }
389
+
390
+ public Instant getSubmittedAt() {
391
+ return submittedAt;
392
+ }
393
+
394
+ public void setSubmittedAt(Instant submittedAt) {
395
+ this.submittedAt = submittedAt;
396
+ }
397
+
398
+ public UUID getSubmittedByUserId() {
399
+ return submittedByUserId;
400
+ }
401
+
402
+ public void setSubmittedByUserId(UUID submittedByUserId) {
403
+ this.submittedByUserId = submittedByUserId;
404
+ }
405
+
406
+ public Instant getApprovedAt() {
407
+ return approvedAt;
408
+ }
409
+
410
+ public void setApprovedAt(Instant approvedAt) {
411
+ this.approvedAt = approvedAt;
412
+ }
413
+
414
+ public UUID getApprovedByUserId() {
415
+ return approvedByUserId;
416
+ }
417
+
418
+ public void setApprovedByUserId(UUID approvedByUserId) {
419
+ this.approvedByUserId = approvedByUserId;
420
+ }
421
+
422
+ public Instant getRejectedAt() {
423
+ return rejectedAt;
424
+ }
425
+
426
+ public void setRejectedAt(Instant rejectedAt) {
427
+ this.rejectedAt = rejectedAt;
428
+ }
429
+
430
+ public UUID getRejectedByUserId() {
431
+ return rejectedByUserId;
432
+ }
433
+
434
+ public void setRejectedByUserId(UUID rejectedByUserId) {
435
+ this.rejectedByUserId = rejectedByUserId;
436
+ }
437
+
438
+ public Instant getPublishedAt() {
439
+ return publishedAt;
440
+ }
441
+
442
+ public void setPublishedAt(Instant publishedAt) {
443
+ this.publishedAt = publishedAt;
444
+ }
445
+
446
+ public UUID getPublishedByUserId() {
447
+ return publishedByUserId;
448
+ }
449
+
450
+ public void setPublishedByUserId(UUID publishedByUserId) {
451
+ this.publishedByUserId = publishedByUserId;
452
+ }
453
+
454
+ /**
455
+ * Utility method to add a review comment.
456
+ */
457
+ public void addReviewComment(String comment, UUID reviewerId, String reviewerRole) {
458
+ Map<String, Object> commentData = Map.of(
459
+ "comment", comment,
460
+ "reviewerId", reviewerId.toString(),
461
+ "reviewerRole", reviewerRole,
462
+ "timestamp", Instant.now().toString()
463
+ );
464
+ this.reviewComments.add(commentData);
465
+ }
466
+
467
+ /**
468
+ * Utility method to add a tag if not already present.
469
+ */
470
+ public void addTag(String tag) {
471
+ if (!this.tags.contains(tag)) {
472
+ this.tags.add(tag);
473
+ }
474
+ }
475
+
476
+ /**
477
+ * Utility method to add a stakeholder if not already present.
478
+ */
479
+ public void addStakeholder(UUID stakeholderId) {
480
+ if (!this.stakeholders.contains(stakeholderId)) {
481
+ this.stakeholders.add(stakeholderId);
482
+ }
483
+ }
484
+
485
+ @PrePersist
486
+ protected void onCreate() {
487
+ createdAt = Instant.now();
488
+ updatedAt = Instant.now();
489
+ }
490
+
491
+ @PreUpdate
492
+ protected void onUpdate() {
493
+ updatedAt = Instant.now();
494
+ }
495
+ }
src/main/java/com/dalab/policyengine/model/PolicyDraftStatus.java ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.model;
2
+
3
+ /**
4
+ * Status enumeration for policy drafts supporting complete workflow lifecycle.
5
+ * Tracks the draft from creation through approval and publication.
6
+ */
7
+ public enum PolicyDraftStatus {
8
+ /**
9
+ * Draft has been created but not yet submitted for review.
10
+ */
11
+ CREATED,
12
+
13
+ /**
14
+ * Draft has been submitted and is awaiting review.
15
+ */
16
+ SUBMITTED,
17
+
18
+ /**
19
+ * Draft is currently under review by approvers.
20
+ */
21
+ UNDER_REVIEW,
22
+
23
+ /**
24
+ * Draft requires changes based on reviewer feedback.
25
+ */
26
+ REQUIRES_CHANGES,
27
+
28
+ /**
29
+ * Draft has been approved and is ready for publication.
30
+ */
31
+ APPROVED,
32
+
33
+ /**
34
+ * Draft has been rejected and will not be published.
35
+ */
36
+ REJECTED,
37
+
38
+ /**
39
+ * Draft has been published as an active policy.
40
+ */
41
+ PUBLISHED,
42
+
43
+ /**
44
+ * Draft has been archived (no longer active).
45
+ */
46
+ ARCHIVED
47
+ }
src/main/java/com/dalab/policyengine/model/PolicyEvaluation.java ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.model;
2
+
3
+ import java.time.Instant;
4
+ import java.util.Map;
5
+ import java.util.UUID;
6
+
7
+ import org.hibernate.annotations.JdbcTypeCode;
8
+ import org.hibernate.type.SqlTypes;
9
+
10
+ import jakarta.persistence.*;
11
+
12
+ @Entity
13
+ @Table(name = "policy_evaluations")
14
+ public class PolicyEvaluation {
15
+
16
+ @Id
17
+ @GeneratedValue(strategy = GenerationType.AUTO)
18
+ @Column(columnDefinition = "UUID")
19
+ private UUID id;
20
+
21
+ @Column(nullable = false, columnDefinition = "UUID")
22
+ private UUID policyId;
23
+
24
+ @Column(nullable = false, length = 255) // External asset ID from da-catalog or other source
25
+ private String targetAssetId;
26
+
27
+ @Enumerated(EnumType.STRING)
28
+ @Column(nullable = false)
29
+ private PolicyEvaluationStatus status;
30
+
31
+ // Store details about the evaluation, e.g., which rules passed/failed, input facts snapshot
32
+ @JdbcTypeCode(SqlTypes.JSON)
33
+ @Column(columnDefinition = "jsonb")
34
+ private Map<String, Object> evaluationDetails;
35
+
36
+ // Store actions that were triggered as a result of this evaluation
37
+ @JdbcTypeCode(SqlTypes.JSON)
38
+ @Column(columnDefinition = "jsonb")
39
+ private Map<String, Object> triggeredActions;
40
+
41
+ @Column(nullable = false)
42
+ private Instant evaluatedAt;
43
+
44
+ @Column(columnDefinition = "UUID")
45
+ private UUID evaluationTriggeredByUserId; // Optional: if triggered by a user action
46
+
47
+ // Getters and Setters
48
+
49
+ public UUID getId() {
50
+ return id;
51
+ }
52
+
53
+ public void setId(UUID id) {
54
+ this.id = id;
55
+ }
56
+
57
+ public UUID getPolicyId() {
58
+ return policyId;
59
+ }
60
+
61
+ public void setPolicyId(UUID policyId) {
62
+ this.policyId = policyId;
63
+ }
64
+
65
+ public String getTargetAssetId() {
66
+ return targetAssetId;
67
+ }
68
+
69
+ public void setTargetAssetId(String targetAssetId) {
70
+ this.targetAssetId = targetAssetId;
71
+ }
72
+
73
+ public PolicyEvaluationStatus getStatus() {
74
+ return status;
75
+ }
76
+
77
+ public void setStatus(PolicyEvaluationStatus status) {
78
+ this.status = status;
79
+ }
80
+
81
+ public Map<String, Object> getEvaluationDetails() {
82
+ return evaluationDetails;
83
+ }
84
+
85
+ public void setEvaluationDetails(Map<String, Object> evaluationDetails) {
86
+ this.evaluationDetails = evaluationDetails;
87
+ }
88
+
89
+ public Map<String, Object> getTriggeredActions() {
90
+ return triggeredActions;
91
+ }
92
+
93
+ public void setTriggeredActions(Map<String, Object> triggeredActions) {
94
+ this.triggeredActions = triggeredActions;
95
+ }
96
+
97
+ public Instant getEvaluatedAt() {
98
+ return evaluatedAt;
99
+ }
100
+
101
+ public void setEvaluatedAt(Instant evaluatedAt) {
102
+ this.evaluatedAt = evaluatedAt;
103
+ }
104
+
105
+ public UUID getEvaluationTriggeredByUserId() {
106
+ return evaluationTriggeredByUserId;
107
+ }
108
+
109
+ public void setEvaluationTriggeredByUserId(UUID evaluationTriggeredByUserId) {
110
+ this.evaluationTriggeredByUserId = evaluationTriggeredByUserId;
111
+ }
112
+
113
+ @PrePersist
114
+ protected void onPersist() {
115
+ if (evaluatedAt == null) {
116
+ evaluatedAt = Instant.now();
117
+ }
118
+ }
119
+ }
src/main/java/com/dalab/policyengine/model/PolicyEvaluationStatus.java ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.model;
2
+
3
+ public enum PolicyEvaluationStatus {
4
+ PASS, // Policy conditions met, actions may have been triggered
5
+ FAIL, // Policy conditions not met
6
+ ERROR, // Error during evaluation (e.g., bad rule syntax, fact unavailable)
7
+ PENDING, // Evaluation is queued or in progress
8
+ NOT_APPLICABLE // Policy was not applicable to the target asset
9
+ }
src/main/java/com/dalab/policyengine/model/PolicyRule.java ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.model;
2
+
3
+ import java.time.Instant;
4
+ import java.util.Map;
5
+ import java.util.UUID;
6
+
7
+ import org.hibernate.annotations.JdbcTypeCode;
8
+ import org.hibernate.type.SqlTypes;
9
+
10
+ import jakarta.persistence.*;
11
+ import jakarta.validation.constraints.NotBlank;
12
+ import jakarta.validation.constraints.Size;
13
+
14
+ @Entity
15
+ @Table(name = "policy_rules")
16
+ public class PolicyRule {
17
+
18
+ @Id
19
+ @GeneratedValue(strategy = GenerationType.AUTO)
20
+ @Column(columnDefinition = "UUID")
21
+ private UUID id;
22
+
23
+ @NotBlank
24
+ @Size(max = 255)
25
+ @Column(nullable = false)
26
+ private String name; // A unique name for the rule within the policy, e.g., "rule1", "checkPII"
27
+
28
+ @Size(max = 1000)
29
+ private String description;
30
+
31
+ @NotBlank
32
+ @Column(nullable = false, columnDefinition = "TEXT")
33
+ private String condition; // MVEL expression, e.g., "asset.assetType == 'S3_BUCKET' && asset.tags.contains('PII')"
34
+
35
+ // Rules with lower numbers have higher priority
36
+ @Column(nullable = false)
37
+ private int priority = 1;
38
+
39
+ // Optional: Actions specific to this rule, if different from policy-level actions or to augment them
40
+ @JdbcTypeCode(SqlTypes.JSON)
41
+ @Column(columnDefinition = "jsonb")
42
+ private Map<String, Object> actions;
43
+
44
+ @ManyToOne(fetch = FetchType.LAZY)
45
+ @JoinColumn(name = "policy_id", nullable = false)
46
+ private Policy policy;
47
+
48
+ @Column(nullable = false, updatable = false)
49
+ private Instant createdAt;
50
+
51
+ private Instant updatedAt;
52
+
53
+ // Getters and Setters
54
+
55
+ public UUID getId() {
56
+ return id;
57
+ }
58
+
59
+ public void setId(UUID id) {
60
+ this.id = id;
61
+ }
62
+
63
+ public String getName() {
64
+ return name;
65
+ }
66
+
67
+ public void setName(String name) {
68
+ this.name = name;
69
+ }
70
+
71
+ public String getDescription() {
72
+ return description;
73
+ }
74
+
75
+ public void setDescription(String description) {
76
+ this.description = description;
77
+ }
78
+
79
+ public String getCondition() {
80
+ return condition;
81
+ }
82
+
83
+ public void setCondition(String condition) {
84
+ this.condition = condition;
85
+ }
86
+
87
+ public int getPriority() {
88
+ return priority;
89
+ }
90
+
91
+ public void setPriority(int priority) {
92
+ this.priority = priority;
93
+ }
94
+
95
+ public Map<String, Object> getActions() {
96
+ return actions;
97
+ }
98
+
99
+ public void setActions(Map<String, Object> actions) {
100
+ this.actions = actions;
101
+ }
102
+
103
+ public Policy getPolicy() {
104
+ return policy;
105
+ }
106
+
107
+ public void setPolicy(Policy policy) {
108
+ this.policy = policy;
109
+ }
110
+
111
+ public Instant getCreatedAt() {
112
+ return createdAt;
113
+ }
114
+
115
+ public void setCreatedAt(Instant createdAt) {
116
+ this.createdAt = createdAt;
117
+ }
118
+
119
+ public Instant getUpdatedAt() {
120
+ return updatedAt;
121
+ }
122
+
123
+ public void setUpdatedAt(Instant updatedAt) {
124
+ this.updatedAt = updatedAt;
125
+ }
126
+
127
+ @PrePersist
128
+ protected void onCreate() {
129
+ createdAt = Instant.now();
130
+ updatedAt = Instant.now();
131
+ }
132
+
133
+ @PreUpdate
134
+ protected void onUpdate() {
135
+ updatedAt = Instant.now();
136
+ }
137
+ }
src/main/java/com/dalab/policyengine/model/PolicyStatus.java ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.model;
2
+
3
+ public enum PolicyStatus {
4
+ ENABLED,
5
+ DISABLED
6
+ }
src/main/java/com/dalab/policyengine/repository/EventRuleRepository.java ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.repository;
2
+
3
+ import java.util.List;
4
+ import java.util.UUID;
5
+
6
+ import org.springframework.data.jpa.repository.JpaRepository;
7
+ import org.springframework.data.jpa.repository.Query;
8
+ import org.springframework.data.repository.query.Param;
9
+ import org.springframework.stereotype.Repository;
10
+
11
+ import com.dalab.policyengine.model.EventRule;
12
+
13
+ /**
14
+ * Repository interface for EventRule entities.
15
+ * Provides data access methods for event rule management.
16
+ */
17
+ @Repository
18
+ public interface EventRuleRepository extends JpaRepository<EventRule, UUID> {
19
+
20
+ /**
21
+ * Find all rules for a specific subscription
22
+ */
23
+ List<EventRule> findBySubscriptionId(UUID subscriptionId);
24
+
25
+ /**
26
+ * Find enabled rules for a specific subscription ordered by priority
27
+ */
28
+ List<EventRule> findBySubscriptionIdAndEnabledTrueOrderByPriorityAsc(UUID subscriptionId);
29
+
30
+ /**
31
+ * Find rules by name pattern
32
+ */
33
+ List<EventRule> findByNameContainingIgnoreCase(String namePattern);
34
+
35
+ /**
36
+ * Find rules for a subscription by name pattern
37
+ */
38
+ List<EventRule> findBySubscriptionIdAndNameContainingIgnoreCase(UUID subscriptionId, String namePattern);
39
+
40
+ /**
41
+ * Check if a rule with the given name already exists for a subscription
42
+ */
43
+ boolean existsBySubscriptionIdAndName(UUID subscriptionId, String name);
44
+
45
+ /**
46
+ * Find rules by enabled status
47
+ */
48
+ List<EventRule> findByEnabled(Boolean enabled);
49
+
50
+ /**
51
+ * Find rules with a specific priority
52
+ */
53
+ List<EventRule> findByPriority(Integer priority);
54
+
55
+ /**
56
+ * Find rules created by a specific user
57
+ */
58
+ List<EventRule> findByCreatedByUserId(UUID createdByUserId);
59
+
60
+ /**
61
+ * Count rules for a specific subscription
62
+ */
63
+ long countBySubscriptionId(UUID subscriptionId);
64
+
65
+ /**
66
+ * Count enabled rules for a specific subscription
67
+ */
68
+ long countBySubscriptionIdAndEnabledTrue(UUID subscriptionId);
69
+
70
+ /**
71
+ * Find rules that contain a specific condition pattern
72
+ */
73
+ @Query("SELECT er FROM EventRule er WHERE er.condition LIKE %:conditionPattern%")
74
+ List<EventRule> findByConditionContaining(@Param("conditionPattern") String conditionPattern);
75
+
76
+ /**
77
+ * Find the highest priority rule for a subscription
78
+ */
79
+ @Query("SELECT er FROM EventRule er WHERE er.subscription.id = :subscriptionId AND er.enabled = true ORDER BY er.priority ASC LIMIT 1")
80
+ EventRule findHighestPriorityEnabledRule(@Param("subscriptionId") UUID subscriptionId);
81
+
82
+ /**
83
+ * Find rules for a subscription ordered by priority
84
+ */
85
+ List<EventRule> findBySubscriptionIdOrderByPriorityAsc(UUID subscriptionId);
86
+ }
src/main/java/com/dalab/policyengine/repository/EventSubscriptionRepository.java ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.repository;
2
+
3
+ import java.util.List;
4
+ import java.util.Optional;
5
+ import java.util.UUID;
6
+
7
+ import org.springframework.data.domain.Page;
8
+ import org.springframework.data.domain.Pageable;
9
+ import org.springframework.data.jpa.repository.JpaRepository;
10
+ import org.springframework.data.jpa.repository.Query;
11
+ import org.springframework.data.repository.query.Param;
12
+ import org.springframework.stereotype.Repository;
13
+
14
+ import com.dalab.policyengine.model.EventSubscription;
15
+ import com.dalab.policyengine.model.EventSubscriptionStatus;
16
+ import com.dalab.policyengine.model.EventType;
17
+
18
+ /**
19
+ * Repository interface for EventSubscription entities.
20
+ * Provides data access methods for event subscription management.
21
+ */
22
+ @Repository
23
+ public interface EventSubscriptionRepository extends JpaRepository<EventSubscription, UUID> {
24
+
25
+ /**
26
+ * Find all event subscriptions for a specific user
27
+ */
28
+ List<EventSubscription> findByUserId(UUID userId);
29
+
30
+ /**
31
+ * Find event subscriptions by user ID with pagination
32
+ */
33
+ Page<EventSubscription> findByUserId(UUID userId, Pageable pageable);
34
+
35
+ /**
36
+ * Find event subscriptions by status
37
+ */
38
+ List<EventSubscription> findByStatus(EventSubscriptionStatus status);
39
+
40
+ /**
41
+ * Find active event subscriptions for a specific user
42
+ */
43
+ List<EventSubscription> findByUserIdAndStatus(UUID userId, EventSubscriptionStatus status);
44
+
45
+ /**
46
+ * Find event subscriptions that monitor a specific event type
47
+ */
48
+ @Query("SELECT es FROM EventSubscription es JOIN es.eventTypes et WHERE et = :eventType AND es.status = 'ACTIVE'")
49
+ List<EventSubscription> findActiveSubscriptionsByEventType(@Param("eventType") EventType eventType);
50
+
51
+ /**
52
+ * Find event subscriptions that monitor a specific source service
53
+ */
54
+ @Query("SELECT es FROM EventSubscription es JOIN es.sourceServices ss WHERE ss = :sourceService AND es.status = 'ACTIVE'")
55
+ List<EventSubscription> findActiveSubscriptionsBySourceService(@Param("sourceService") String sourceService);
56
+
57
+ /**
58
+ * Find event subscriptions by name pattern
59
+ */
60
+ List<EventSubscription> findByNameContainingIgnoreCase(String namePattern);
61
+
62
+ /**
63
+ * Find event subscriptions for a user by name pattern
64
+ */
65
+ List<EventSubscription> findByUserIdAndNameContainingIgnoreCase(UUID userId, String namePattern);
66
+
67
+ /**
68
+ * Check if a subscription with the given name already exists for a user
69
+ */
70
+ boolean existsByUserIdAndName(UUID userId, String name);
71
+
72
+ /**
73
+ * Find active subscriptions that could match an event based on event type and source service
74
+ */
75
+ @Query("SELECT DISTINCT es FROM EventSubscription es " +
76
+ "LEFT JOIN es.eventTypes et " +
77
+ "LEFT JOIN es.sourceServices ss " +
78
+ "WHERE es.status = 'ACTIVE' " +
79
+ "AND (et = :eventType OR es.eventTypes IS EMPTY) " +
80
+ "AND (ss = :sourceService OR es.sourceServices IS EMPTY)")
81
+ List<EventSubscription> findPotentialMatchingSubscriptions(
82
+ @Param("eventType") EventType eventType,
83
+ @Param("sourceService") String sourceService);
84
+
85
+ /**
86
+ * Count active subscriptions for a user
87
+ */
88
+ long countByUserIdAndStatus(UUID userId, EventSubscriptionStatus status);
89
+
90
+ /**
91
+ * Find subscriptions created by a specific user
92
+ */
93
+ List<EventSubscription> findByCreatedByUserId(UUID createdByUserId);
94
+
95
+ /**
96
+ * Find subscriptions with a specific notification type enabled
97
+ */
98
+ @Query("SELECT es FROM EventSubscription es WHERE jsonb_extract_path_text(CAST(es.notificationConfig AS text), :notificationType) = 'true'")
99
+ List<EventSubscription> findSubscriptionsWithNotificationType(@Param("notificationType") String notificationType);
100
+ }
src/main/java/com/dalab/policyengine/repository/PolicyDraftRepository.java ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.dalab.policyengine.repository;
2
+
3
+ import java.time.Instant;
4
+ import java.util.List;
5
+ import java.util.UUID;
6
+
7
+ import org.springframework.data.domain.Page;
8
+ import org.springframework.data.domain.Pageable;
9
+ import org.springframework.data.jpa.repository.JpaRepository;
10
+ import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
11
+ import org.springframework.data.jpa.repository.Query;
12
+ import org.springframework.data.repository.query.Param;
13
+ import org.springframework.stereotype.Repository;
14
+
15
+ import com.dalab.policyengine.model.PolicyDraft;
16
+ import com.dalab.policyengine.model.PolicyDraftStatus;
17
+
18
+ /**
19
+ * Repository interface for PolicyDraft entities.
20
+ * Provides comprehensive query methods for draft management and workflow operations.
21
+ */
22
+ @Repository
23
+ public interface PolicyDraftRepository extends JpaRepository<PolicyDraft, UUID>, JpaSpecificationExecutor<PolicyDraft> {
24
+
25
+ /**
26
+ * Find all drafts by their current status.
27
+ */
28
+ Page<PolicyDraft> findByStatus(PolicyDraftStatus status, Pageable pageable);
29
+
30
+ /**
31
+ * Find all drafts created by a specific user.
32
+ */
33
+ Page<PolicyDraft> findByCreatedByUserId(UUID createdByUserId, Pageable pageable);
34
+
35
+ /**
36
+ * Find all drafts where the user is a stakeholder.
37
+ */
38
+ @Query("SELECT pd FROM PolicyDraft pd WHERE :userId MEMBER OF pd.stakeholders")
39
+ Page<PolicyDraft> findByStakeholder(@Param("userId") UUID userId, Pageable pageable);
40
+
41
+ /**
42
+ * Find all drafts pending review (submitted or under review).
43
+ */
44
+ @Query("SELECT pd FROM PolicyDraft pd WHERE pd.status IN ('SUBMITTED', 'UNDER_REVIEW')")
45
+ Page<PolicyDraft> findPendingReview(Pageable pageable);
46
+
47
+ /**
48
+ * Find all drafts that require attention from a specific user (created by them or they are stakeholder).
49
+ */
50
+ @Query("SELECT DISTINCT pd FROM PolicyDraft pd WHERE pd.createdByUserId = :userId OR :userId MEMBER OF pd.stakeholders")
51
+ Page<PolicyDraft> findRequiringAttention(@Param("userId") UUID userId, Pageable pageable);
52
+
53
+ /**
54
+ * Find drafts by name containing specific text (case insensitive).
55
+ */
56
+ Page<PolicyDraft> findByNameContainingIgnoreCase(String name, Pageable pageable);
57
+
58
+ /**
59
+ * Find drafts by category.
60
+ */
61
+ Page<PolicyDraft> findByCategory(String category, Pageable pageable);
62
+
63
+ /**
64
+ * Find drafts by priority level.
65
+ */
66
+ Page<PolicyDraft> findByPriority(String priority, Pageable pageable);
67
+
68
+ /**
69
+ * Find drafts that are based on a specific policy (updates to existing policies).
70
+ */
71
+ List<PolicyDraft> findByBasePolicyId(UUID basePolicyId);
72
+
73
+ /**
74
+ * Find the latest version of drafts for a specific base policy.
75
+ */
76
+ @Query("SELECT pd FROM PolicyDraft pd WHERE pd.basePolicyId = :basePolicyId ORDER BY pd.version DESC")
77
+ List<PolicyDraft> findLatestVersionByBasePolicyId(@Param("basePolicyId") UUID basePolicyId);
78
+
79
+ /**
80
+ * Find drafts with target implementation date before specified date.
81
+ */
82
+ List<PolicyDraft> findByTargetImplementationDateBefore(Instant date);
83
+
84
+ /**
85
+ * Find drafts created within a specific time range.
86
+ */
87
+ Page<PolicyDraft> findByCreatedAtBetween(Instant startDate, Instant endDate, Pageable pageable);
88
+
89
+ /**
90
+ * Find drafts that have been in a specific status for longer than specified time.
91
+ */
92
+ @Query("SELECT pd FROM PolicyDraft pd WHERE pd.status = :status AND pd.updatedAt < :cutoffTime")
93
+ List<PolicyDraft> findStaleInStatus(@Param("status") PolicyDraftStatus status, @Param("cutoffTime") Instant cutoffTime);
94
+
95
+ /**
96
+ * Find drafts containing specific tags.
97
+ */
98
+ @Query("SELECT pd FROM PolicyDraft pd WHERE :tag MEMBER OF pd.tags")
99
+ Page<PolicyDraft> findByTag(@Param("tag") String tag, Pageable pageable);
100
+
101
+ /**
102
+ * Find drafts by multiple criteria (complex search).
103
+ */
104
+ @Query("SELECT pd FROM PolicyDraft pd WHERE " +
105
+ "(:status IS NULL OR pd.status = :status) AND " +
106
+ "(:category IS NULL OR pd.category = :category) AND " +
107
+ "(:priority IS NULL OR pd.priority = :priority) AND " +
108
+ "(:createdBy IS NULL OR pd.createdByUserId = :createdBy) AND " +
109
+ "(:nameFilter IS NULL OR LOWER(pd.name) LIKE LOWER(CONCAT('%', :nameFilter, '%')))")
110
+ Page<PolicyDraft> findByCriteria(
111
+ @Param("status") PolicyDraftStatus status,
112
+ @Param("category") String category,
113
+ @Param("priority") String priority,
114
+ @Param("createdBy") UUID createdBy,
115
+ @Param("nameFilter") String nameFilter,
116
+ Pageable pageable
117
+ );
118
+
119
+ /**
120
+ * Count drafts by status.
121
+ */
122
+ long countByStatus(PolicyDraftStatus status);
123
+
124
+ /**
125
+ * Count drafts created by a specific user.
126
+ */
127
+ long countByCreatedByUserId(UUID createdByUserId);
128
+
129
+ /**
130
+ * Check if a draft name already exists (for validation).
131
+ */
132
+ boolean existsByName(String name);
133
+
134
+ /**
135
+ * Check if a draft name exists excluding a specific draft (for updates).
136
+ */
137
+ @Query("SELECT CASE WHEN COUNT(pd) > 0 THEN true ELSE false END FROM PolicyDraft pd WHERE pd.name = :name AND pd.id != :excludeId")
138
+ boolean existsByNameExcludingId(@Param("name") String name, @Param("excludeId") UUID excludeId);
139
+
140
+ /**
141
+ * Find all distinct categories used in drafts.
142
+ */
143
+ @Query("SELECT DISTINCT pd.category FROM PolicyDraft pd WHERE pd.category IS NOT NULL")
144
+ List<String> findAllCategories();
145
+
146
+ /**
147
+ * Find all distinct tags used in drafts.
148
+ */
149
+ @Query("SELECT DISTINCT tag FROM PolicyDraft pd JOIN pd.tags tag")
150
+ List<String> findAllTags();
151
+
152
+ /**
153
+ * Get draft statistics for dashboard.
154
+ */
155
+ @Query("SELECT pd.status, COUNT(pd) FROM PolicyDraft pd GROUP BY pd.status")
156
+ List<Object[]> getDraftStatisticsByStatus();
157
+
158
+ /**
159
+ * Get drafts summary by user.
160
+ */
161
+ @Query("SELECT pd.createdByUserId, pd.status, COUNT(pd) FROM PolicyDraft pd GROUP BY pd.createdByUserId, pd.status")
162
+ List<Object[]> getDraftStatisticsByUser();
163
+
164
+ /**
165
+ * Find overdue drafts (target implementation date passed and still not published).
166
+ */
167
+ @Query("SELECT pd FROM PolicyDraft pd WHERE pd.targetImplementationDate < :currentDate AND pd.status != 'PUBLISHED' AND pd.status != 'REJECTED' AND pd.status != 'ARCHIVED'")
168
+ List<PolicyDraft> findOverdueDrafts(@Param("currentDate") Instant currentDate);
169
+ }