From e354c4056d3264ec15a461614f7ff2b0cba191b5 Mon Sep 17 00:00:00 2001 From: sushi30 Date: Tue, 28 Jan 2025 20:07:32 +0100 Subject: [PATCH] feat(event-subscriptions): event consumer extension - implemented DI for event consumers - added custom config for event consumers - initialize the event scheduler along with application - added workflow custom type --- .../service/OpenMetadataApplication.java | 1 + .../changeEvent/AbstractEventConsumer.java | 7 ++- .../bundles/changeEvent/AlertPublisher.java | 4 ++ .../events/scheduled/ConsumerService.java | 8 +++ .../events/scheduled/ConsumerServiceImpl.java | 19 +++++++ .../scheduled/EventSubscriptionScheduler.java | 48 ++++++++++++++--- .../jdbi3/EventSubscriptionRepository.java | 1 + .../subscription/EventSubscriptionMapper.java | 3 +- .../EventSubscriptionResource.java | 2 +- .../service/util/DIContainer.java | 20 +++++++ .../schema/entity/automations/workflow.json | 13 ++++- .../events/api/createEventSubscription.json | 3 ++ .../json/schema/events/eventSubscription.json | 3 ++ .../generated/entity/automations/workflow.ts | 52 ++++++++++++++----- .../events/api/createEventSubscription.ts | 1 + .../src/generated/events/eventSubscription.ts | 1 + 16 files changed, 161 insertions(+), 25 deletions(-) create mode 100644 openmetadata-service/src/main/java/org/openmetadata/service/events/scheduled/ConsumerService.java create mode 100644 openmetadata-service/src/main/java/org/openmetadata/service/events/scheduled/ConsumerServiceImpl.java create mode 100644 openmetadata-service/src/main/java/org/openmetadata/service/util/DIContainer.java diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/OpenMetadataApplication.java b/openmetadata-service/src/main/java/org/openmetadata/service/OpenMetadataApplication.java index ee00e54cf121..158e910582cc 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/OpenMetadataApplication.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/OpenMetadataApplication.java @@ -234,6 +234,7 @@ public void run(OpenMetadataApplicationConfig catalogConfig, Environment environ EventPubSub.start(); ApplicationHandler.initialize(catalogConfig); + EventSubscriptionScheduler.initialize(catalogConfig); registerResources(catalogConfig, environment, jdbi); // Register Event Handler diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/apps/bundles/changeEvent/AbstractEventConsumer.java b/openmetadata-service/src/main/java/org/openmetadata/service/apps/bundles/changeEvent/AbstractEventConsumer.java index a0a11f031205..fc184754e48c 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/apps/bundles/changeEvent/AbstractEventConsumer.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/apps/bundles/changeEvent/AbstractEventConsumer.java @@ -35,6 +35,7 @@ import org.openmetadata.schema.type.ChangeEvent; import org.openmetadata.service.Entity; import org.openmetadata.service.events.errors.EventPublisherException; +import org.openmetadata.service.events.scheduled.ConsumerService; import org.openmetadata.service.util.JsonUtils; import org.quartz.DisallowConcurrentExecution; import org.quartz.Job; @@ -53,7 +54,7 @@ public abstract class AbstractEventConsumer public static final String OFFSET_EXTENSION = "eventSubscription.Offset"; public static final String METRICS_EXTENSION = "eventSubscription.metrics"; public static final String FAILED_EVENT_EXTENSION = "eventSubscription.failedEvent"; - + protected final ConsumerService consumerService; private long offset = -1; private long startingOffset = -1; @@ -63,7 +64,9 @@ public abstract class AbstractEventConsumer protected EventSubscription eventSubscription; protected Map> destinationMap; - protected AbstractEventConsumer() {} + protected AbstractEventConsumer(ConsumerService consumerService) { + this.consumerService = consumerService; + } private void init(JobExecutionContext context) { EventSubscription sub = diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/apps/bundles/changeEvent/AlertPublisher.java b/openmetadata-service/src/main/java/org/openmetadata/service/apps/bundles/changeEvent/AlertPublisher.java index ccd6017dd361..5f585e268a51 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/apps/bundles/changeEvent/AlertPublisher.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/apps/bundles/changeEvent/AlertPublisher.java @@ -4,9 +4,13 @@ import lombok.extern.slf4j.Slf4j; import org.openmetadata.schema.type.ChangeEvent; import org.openmetadata.service.events.errors.EventPublisherException; +import org.openmetadata.service.events.scheduled.ConsumerService; @Slf4j public class AlertPublisher extends AbstractEventConsumer { + public AlertPublisher(ConsumerService consumerService) { + super(consumerService); + } @Override public void sendAlert(UUID receiverId, ChangeEvent event) throws EventPublisherException { diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/events/scheduled/ConsumerService.java b/openmetadata-service/src/main/java/org/openmetadata/service/events/scheduled/ConsumerService.java new file mode 100644 index 000000000000..baa7d12dd86e --- /dev/null +++ b/openmetadata-service/src/main/java/org/openmetadata/service/events/scheduled/ConsumerService.java @@ -0,0 +1,8 @@ +package org.openmetadata.service.events.scheduled; + +import org.openmetadata.schema.entity.automations.Workflow; +import org.openmetadata.schema.entity.services.ingestionPipelines.PipelineServiceClientResponse; + +public interface ConsumerService { + PipelineServiceClientResponse runAutomationWorkflow(Workflow wf); +} diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/events/scheduled/ConsumerServiceImpl.java b/openmetadata-service/src/main/java/org/openmetadata/service/events/scheduled/ConsumerServiceImpl.java new file mode 100644 index 000000000000..6a4f471917c8 --- /dev/null +++ b/openmetadata-service/src/main/java/org/openmetadata/service/events/scheduled/ConsumerServiceImpl.java @@ -0,0 +1,19 @@ +package org.openmetadata.service.events.scheduled; + +import org.openmetadata.schema.entity.automations.Workflow; +import org.openmetadata.schema.entity.services.ingestionPipelines.PipelineServiceClientResponse; +import org.openmetadata.sdk.PipelineServiceClientInterface; +import org.openmetadata.service.util.DIContainer; + +public class ConsumerServiceImpl implements ConsumerService { + private final DIContainer di; + + public ConsumerServiceImpl(DIContainer diContainer) { + di = diContainer; + } + + @Override + public PipelineServiceClientResponse runAutomationWorkflow(Workflow wf) { + return di.getResource(PipelineServiceClientInterface.class).runAutomationsWorkflow(wf); + } +} diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/events/scheduled/EventSubscriptionScheduler.java b/openmetadata-service/src/main/java/org/openmetadata/service/events/scheduled/EventSubscriptionScheduler.java index e8ce32bb0a00..253832509264 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/events/scheduled/EventSubscriptionScheduler.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/events/scheduled/EventSubscriptionScheduler.java @@ -37,14 +37,19 @@ import org.openmetadata.schema.entity.events.SubscriptionDestination; import org.openmetadata.schema.entity.events.SubscriptionStatus; import org.openmetadata.schema.type.ChangeEvent; +import org.openmetadata.sdk.PipelineServiceClientInterface; import org.openmetadata.service.Entity; +import org.openmetadata.service.OpenMetadataApplicationConfig; import org.openmetadata.service.apps.bundles.changeEvent.AbstractEventConsumer; import org.openmetadata.service.apps.bundles.changeEvent.AlertPublisher; +import org.openmetadata.service.clients.pipeline.PipelineServiceClientFactory; import org.openmetadata.service.events.subscription.AlertUtil; import org.openmetadata.service.jdbi3.EntityRepository; import org.openmetadata.service.jdbi3.EventSubscriptionRepository; import org.openmetadata.service.resources.events.subscription.TypedEvent; +import org.openmetadata.service.util.DIContainer; import org.openmetadata.service.util.JsonUtils; +import org.quartz.Job; import org.quartz.JobBuilder; import org.quartz.JobDataMap; import org.quartz.JobDetail; @@ -56,6 +61,8 @@ import org.quartz.TriggerBuilder; import org.quartz.TriggerKey; import org.quartz.impl.StdSchedulerFactory; +import org.quartz.spi.JobFactory; +import org.quartz.spi.TriggerFiredBundle; @Slf4j public class EventSubscriptionScheduler { @@ -63,24 +70,51 @@ public class EventSubscriptionScheduler { public static final String ALERT_TRIGGER_GROUP = "OMAlertJobGroup"; private static EventSubscriptionScheduler instance; private static volatile boolean initialized = false; - private final Scheduler alertsScheduler = new StdSchedulerFactory().getScheduler(); - private EventSubscriptionScheduler() throws SchedulerException { + private record CustomJobFactory(ConsumerService consumerService) implements JobFactory { + + @Override + public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException { + try { + JobDetail jobDetail = bundle.getJobDetail(); + Class jobClass = jobDetail.getJobClass(); + Job job = + jobClass.getDeclaredConstructor(ConsumerService.class).newInstance(consumerService); + return job; + } catch (Exception e) { + throw new SchedulerException("Failed to create job instance", e); + } + } + } + + private EventSubscriptionScheduler(PipelineServiceClientInterface pipelineServiceClient) + throws SchedulerException { + DIContainer di = new DIContainer(); + di.registerResource(PipelineServiceClientInterface.class, pipelineServiceClient); + ConsumerService consumerService = new ConsumerServiceImpl(di); + this.alertsScheduler.setJobFactory(new CustomJobFactory(consumerService)); this.alertsScheduler.start(); } @SneakyThrows public static EventSubscriptionScheduler getInstance() { if (!initialized) { - initialize(); + throw new RuntimeException("Event Subscription Scheduler is not initialized"); } return instance; } - private static void initialize() throws SchedulerException { + public static void initialize(OpenMetadataApplicationConfig openMetadataApplicationConfig) { + PipelineServiceClientInterface pipelineServiceClient = + PipelineServiceClientFactory.createPipelineServiceClient( + openMetadataApplicationConfig.getPipelineServiceClientConfiguration()); if (!initialized) { - instance = new EventSubscriptionScheduler(); + try { + instance = new EventSubscriptionScheduler(pipelineServiceClient); + } catch (SchedulerException e) { + throw new RuntimeException("Failed to initialize Event Subscription Scheduler", e); + } initialized = true; } else { LOG.info("Event Subscription Scheduler is already initialized"); @@ -101,7 +135,9 @@ public void addSubscriptionPublisher(EventSubscription eventSubscription, boolea Optional.ofNullable(eventSubscription.getClassName()) .orElse(defaultClass.getCanonicalName())) .asSubclass(AbstractEventConsumer.class); - AbstractEventConsumer publisher = clazz.getDeclaredConstructor().newInstance(); + ConsumerService consumerService = new ConsumerServiceImpl(null); + AbstractEventConsumer publisher = + clazz.getDeclaredConstructor(ConsumerService.class).newInstance(consumerService); if (reinstall && isSubscriptionRegistered(eventSubscription)) { deleteEventSubscriptionPublisher(eventSubscription); } diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EventSubscriptionRepository.java b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EventSubscriptionRepository.java index 2eefbef79458..58ec665b7a0a 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EventSubscriptionRepository.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EventSubscriptionRepository.java @@ -149,6 +149,7 @@ public void entitySpecificUpdate(boolean consolidatingChanges) { objectMatch, false); recordChange("trigger", original.getTrigger(), updated.getTrigger(), true); + recordChange("config", original.getConfig(), updated.getConfig(), true); } } } diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/resources/events/subscription/EventSubscriptionMapper.java b/openmetadata-service/src/main/java/org/openmetadata/service/resources/events/subscription/EventSubscriptionMapper.java index df694a1ddd97..3e35c5d6c246 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/resources/events/subscription/EventSubscriptionMapper.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/resources/events/subscription/EventSubscriptionMapper.java @@ -36,7 +36,8 @@ public EventSubscription createToEntity(CreateEventSubscription create, String u .withClassName( validateConsumerClass( Optional.ofNullable(create.getClassName()) - .orElse(AlertPublisher.class.getCanonicalName()))); + .orElse(AlertPublisher.class.getCanonicalName()))) + .withConfig(create.getConfig()); } private String validateConsumerClass(String className) { diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/resources/events/subscription/EventSubscriptionResource.java b/openmetadata-service/src/main/java/org/openmetadata/service/resources/events/subscription/EventSubscriptionResource.java index d575fbf01c3d..98ee11b416fb 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/resources/events/subscription/EventSubscriptionResource.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/resources/events/subscription/EventSubscriptionResource.java @@ -102,7 +102,7 @@ "The `Events` are changes to metadata and are sent when entities are created, modified, or updated. External systems can subscribe to events using event subscription API over Webhooks, Slack, or Microsoft Teams.") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -@Collection(name = "events/subscriptions") +@Collection(name = "events/subscriptions", order = 7) // needs to initialize before applications public class EventSubscriptionResource extends EntityResource { public static final String COLLECTION_PATH = "/v1/events/subscriptions"; diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/util/DIContainer.java b/openmetadata-service/src/main/java/org/openmetadata/service/util/DIContainer.java new file mode 100644 index 000000000000..85ea0f3834a6 --- /dev/null +++ b/openmetadata-service/src/main/java/org/openmetadata/service/util/DIContainer.java @@ -0,0 +1,20 @@ +package org.openmetadata.service.util; + +import java.util.HashMap; +import java.util.Map; + +public class DIContainer { + private final Map, Object> resources = new HashMap<>(); + + public void registerResource(Class resourceClass, T resource) { + resources.put(resourceClass, resource); + } + + public T getResource(Class resourceClass) { + T resource = resourceClass.cast(resources.get(resourceClass)); + if (resource == null) { + throw new IllegalStateException("Resource not initialized: " + resourceClass.getName()); + } + return resource; + } +} diff --git a/openmetadata-spec/src/main/resources/json/schema/entity/automations/workflow.json b/openmetadata-spec/src/main/resources/json/schema/entity/automations/workflow.json index 0616be5055a9..f279c88f9ad9 100644 --- a/openmetadata-spec/src/main/resources/json/schema/entity/automations/workflow.json +++ b/openmetadata-spec/src/main/resources/json/schema/entity/automations/workflow.json @@ -12,7 +12,8 @@ "description": "This enum defines the type for which this workflow applies to.", "type": "string", "enum": [ - "TEST_CONNECTION" + "TEST_CONNECTION", + "CUSTOM" ] }, "workflowStatus": { @@ -47,6 +48,10 @@ "description": "Type of the workflow.", "$ref": "#/definitions/workflowType" }, + "pythonClass": { + "description": "Python class to be executed for this workflow (for custom workflows)", + "type": "string" + }, "status": { "description": "Workflow computation status.", "$ref": "#/definitions/workflowStatus", @@ -57,6 +62,9 @@ "oneOf": [ { "$ref": "testServiceConnection.json" + }, + { + "$ref": "../../type/basic.json#/definitions/map" } ] }, @@ -65,6 +73,9 @@ "oneOf": [ { "$ref": "../services/connections/testConnectionResult.json" + }, + { + "$ref": "../../type/basic.json#/definitions/map" } ] }, diff --git a/openmetadata-spec/src/main/resources/json/schema/events/api/createEventSubscription.json b/openmetadata-spec/src/main/resources/json/schema/events/api/createEventSubscription.json index d21e07f750b5..672c0930741f 100644 --- a/openmetadata-spec/src/main/resources/json/schema/events/api/createEventSubscription.json +++ b/openmetadata-spec/src/main/resources/json/schema/events/api/createEventSubscription.json @@ -79,6 +79,9 @@ "domain" : { "description": "Fully qualified name of the domain the Table belongs to.", "type": "string" + }, + "config": { + "$ref": "../../type/basic.json#/definitions/map" } }, "required": ["name", "alertType"], diff --git a/openmetadata-spec/src/main/resources/json/schema/events/eventSubscription.json b/openmetadata-spec/src/main/resources/json/schema/events/eventSubscription.json index 596536916e50..2d362132b9a8 100644 --- a/openmetadata-spec/src/main/resources/json/schema/events/eventSubscription.json +++ b/openmetadata-spec/src/main/resources/json/schema/events/eventSubscription.json @@ -328,6 +328,9 @@ "domain" : { "description": "Domain the asset belongs to. When not set, the asset inherits the domain from the parent it belongs to.", "$ref": "../type/entityReference.json" + }, + "config": { + "$ref": "../type/basic.json#/definitions/map" } }, "required": ["id", "name", "alertType", "destinations"], diff --git a/openmetadata-ui/src/main/resources/ui/src/generated/entity/automations/workflow.ts b/openmetadata-ui/src/main/resources/ui/src/generated/entity/automations/workflow.ts index 18528ea0fd67..29753c377370 100644 --- a/openmetadata-ui/src/main/resources/ui/src/generated/entity/automations/workflow.ts +++ b/openmetadata-ui/src/main/resources/ui/src/generated/entity/automations/workflow.ts @@ -1,5 +1,5 @@ /* - * Copyright 2024 Collate. + * Copyright 2025 Collate. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -10,9 +10,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - - - /** +/** * A unit of work that will be triggered as an API call to the OpenMetadata server. */ export interface Workflow { @@ -62,6 +60,10 @@ export interface Workflow { * Owners of this workflow. */ owners?: EntityReference[]; + /** + * Python class to be executed for this workflow (for custom workflows) + */ + pythonClass?: string; /** * Request body for a specific workflow type */ @@ -297,7 +299,7 @@ export interface OpenMetadataConnection { /** * SSL Configuration for OpenMetadata Server */ - sslConfig?: SchemaRegistrySSLClass; + sslConfig?: ConsumerConfigSSLClass; /** * If set to true, when creating a service during the ingestion we will store its Service * Connection. Otherwise, the ingestion will create a bare service without connection @@ -403,12 +405,15 @@ export interface OpenMetadataJWTClientConfig { * * SSL Configuration details. * + * Consumer Config SSL Config. Configuration for enabling SSL for the Consumer Config + * connection. + * * Schema Registry SSL Config. Configuration for enabling SSL for the Schema Registry * connection. * * OpenMetadata Client configured to validate SSL certificates. */ -export interface SchemaRegistrySSLClass { +export interface ConsumerConfigSSLClass { /** * The CA certificate used for SSL validation. */ @@ -447,6 +452,8 @@ export enum VerifySSL { * Request body for a specific workflow type * * Test Service Connection to test user provided configuration is valid or not. + * + * A generic map that can be deserialized later. */ export interface TestServiceConnectionRequest { /** @@ -469,6 +476,7 @@ export interface TestServiceConnectionRequest { * Type of service such as Database, Dashboard, Messaging, etc. */ serviceType?: ServiceType; + [property: string]: any; } /** @@ -875,10 +883,11 @@ export interface ConfigClass { * * Http/Https connection scheme */ - scheme?: string; - supportsDatabase?: boolean; - supportsDataDiff?: boolean; - supportsDBTExtraction?: boolean; + scheme?: string; + supportsDatabase?: boolean; + supportsDataDiff?: boolean; + supportsDBTExtraction?: boolean; + supportsIncrementalMetadataExtraction?: boolean; /** * Supports Lineage Extraction. */ @@ -1639,6 +1648,11 @@ export interface ConfigClass { * Confluent Redpanda Consumer Config */ consumerConfig?: { [key: string]: any }; + /** + * Consumer Config SSL Config. Configuration for enabling SSL for the Consumer Config + * connection. + */ + consumerConfigSSL?: ConsumerConfigSSLClass; /** * sasl.mechanism Consumer Config property */ @@ -1662,7 +1676,7 @@ export interface ConfigClass { * Schema Registry SSL Config. Configuration for enabling SSL for the Schema Registry * connection. */ - schemaRegistrySSL?: SchemaRegistrySSLClass; + schemaRegistrySSL?: ConsumerConfigSSLClass; /** * Schema Registry Topic Suffix Name. The suffix to be appended to the topic name to get * topic schema from registry. @@ -2459,7 +2473,7 @@ export interface SSLCertificatesByPath { * Qlik Authentication Certificate File Path */ export interface QlikCertificatesBy { - sslConfig?: SchemaRegistrySSLClass; + sslConfig?: ConsumerConfigSSLClass; /** * Client Certificate */ @@ -3049,6 +3063,9 @@ export enum ConnectionScheme { * * SSL Configuration details. * + * Consumer Config SSL Config. Configuration for enabling SSL for the Consumer Config + * connection. + * * Schema Registry SSL Config. Configuration for enabling SSL for the Schema Registry * connection. */ @@ -3265,7 +3282,7 @@ export interface HiveMetastoreConnectionDetails { /** * SSL Configuration details. */ - sslConfig?: SchemaRegistrySSLClass; + sslConfig?: ConsumerConfigSSLClass; sslMode?: SSLMode; supportsDatabase?: boolean; supportsDataDiff?: boolean; @@ -3502,6 +3519,9 @@ export enum KafkaSecurityProtocol { * * SSL Configuration details. * + * Consumer Config SSL Config. Configuration for enabling SSL for the Consumer Config + * connection. + * * Schema Registry SSL Config. Configuration for enabling SSL for the Schema Registry * connection. * @@ -3788,6 +3808,8 @@ export enum ServiceType { * * TestConnectionResult is the definition that will encapsulate result of running the test * connection steps. + * + * A generic map that can be deserialized later. */ export interface TestConnectionResult { /** @@ -3801,7 +3823,8 @@ export interface TestConnectionResult { /** * Steps to test the connection. Order matters. */ - steps: TestConnectionStepResult[]; + steps?: TestConnectionStepResult[]; + [property: string]: any; } /** @@ -3861,5 +3884,6 @@ export enum WorkflowStatus { * This enum defines the type for which this workflow applies to. */ export enum WorkflowType { + Custom = "CUSTOM", TestConnection = "TEST_CONNECTION", } diff --git a/openmetadata-ui/src/main/resources/ui/src/generated/events/api/createEventSubscription.ts b/openmetadata-ui/src/main/resources/ui/src/generated/events/api/createEventSubscription.ts index d7a75280f013..d1d120a8303a 100644 --- a/openmetadata-ui/src/main/resources/ui/src/generated/events/api/createEventSubscription.ts +++ b/openmetadata-ui/src/main/resources/ui/src/generated/events/api/createEventSubscription.ts @@ -26,6 +26,7 @@ export interface CreateEventSubscription { * Consumer Class for the Event Subscription. Will use 'AlertPublisher' if not provided. */ className?: string; + config?: { [key: string]: any }; /** * A short description of the Alert, comprehensible to regular users. */ diff --git a/openmetadata-ui/src/main/resources/ui/src/generated/events/eventSubscription.ts b/openmetadata-ui/src/main/resources/ui/src/generated/events/eventSubscription.ts index 6f658bb19ff4..10f25efd1879 100644 --- a/openmetadata-ui/src/main/resources/ui/src/generated/events/eventSubscription.ts +++ b/openmetadata-ui/src/main/resources/ui/src/generated/events/eventSubscription.ts @@ -31,6 +31,7 @@ export interface EventSubscription { * Java class for the Event Subscription. */ className?: string; + config?: { [key: string]: any }; /** * A short description of the Event Subscription, comprehensible to regular users. */