Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions openmetadata-dsl/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.open-metadata</groupId>
<artifactId>platform</artifactId>
<version>1.12.0-SNAPSHOT</version>
</parent>

<artifactId>openmetadata-dsl</artifactId>
<name>OpenMetadata DSL</name>
<description>
OpenMetadata DSL (Domain-Specific Language) enables users to create sophisticated
alert rules, governance policies, and automation workflows using natural, expressive syntax.
</description>

<dependencies>
<dependency>
<groupId>org.open-metadata</groupId>
<artifactId>openmetadata-spec</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.open-metadata</groupId>
<artifactId>openmetadata-service</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId>
<version>4.9.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>6.1.14</version>
</dependency>
Comment on lines +33 to +40
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Quality: Unused antlr4 and spring-core deps with version conflicts

The openmetadata-dsl/pom.xml declares dependencies on antlr4-runtime:4.9.3 and spring-core:6.1.14, but neither is imported or used anywhere in the module's source code. The parser is hand-written using java.util.regex. Additionally, these hardcoded versions conflict with the parent POM's managed versions (antlr:4.13.2, spring:6.2.11), which could cause classpath issues at runtime if the module is included in a larger build. Remove unused dependencies or, if they are planned for future use, at least use ${antlr.version} / ${spring.version} from the parent POM.

Suggested fix:

Remove the unused dependencies:
<!-- Remove these from pom.xml -->
<dependency>
  <groupId>org.antlr</groupId>
  <artifactId>antlr4-runtime</artifactId>
  ...
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  ...
</dependency>

Was this helpful? React with 👍 / 👎 | Reply gitar fix to apply this suggestion

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
Comment thread
gitar-bot[bot] marked this conversation as resolved.
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2026 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
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openmetadata.dsl;

import java.util.List;
import lombok.Builder;
import lombok.Data;
import org.openmetadata.schema.EntityInterface;
import org.openmetadata.schema.type.ChangeEvent;

/**
* DSL Evaluation Context - holds the data needed to evaluate DSL expressions.
*/
@Data
@Builder
public class DSLContext {

/** The entity being evaluated */
private EntityInterface entity;

/** Change event if this is triggered by an entity change */
private ChangeEvent changeEvent;

/** Additional variables defined in the expression */
private List<DSLVariable> variables;
}
207 changes: 207 additions & 0 deletions openmetadata-dsl/src/main/java/org/openmetadata/dsl/DSLExamples.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
/*
* Copyright 2026 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
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openmetadata.dsl;

import lombok.extern.slf4j.Slf4j;

/**
* Examples demonstrating OpenMetadata DSL usage.
*/
@Slf4j
public class DSLExamples {

public static void main(String[] args) {
log.info("=== OpenMetadata DSL Examples ===\n");

OpenMetadataDSL dsl = new OpenMetadataDSL();

// Example 1: Basic entity check
exampleBasicEntityCheck(dsl);

// Example 2: Data quality monitoring
exampleDataQualityMonitoring(dsl);

// Example 3: Compliance check
exampleComplianceCheck(dsl);

// Example 4: Security monitoring
exampleSecurityMonitoring(dsl);

log.info("\n=== Examples Complete ===");
}

private static void exampleBasicEntityCheck(OpenMetadataDSL dsl) {
log.info("--- Example 1: Basic Entity Check ---");

String rule = "entity.entityType == 'table' AND hasTag('Business-Critical')";

DSLContext context = DSLContext.builder()
.entity(createMockEntity("users", "table"))
.build();

boolean result = dsl.evaluateCondition(rule, context);
log.info("Rule: {}", rule);
log.info("Result: {}", result);
log.info("");
}

private static void exampleDataQualityMonitoring(OpenMetadataDSL dsl) {
log.info("--- Example 2: Data Quality Monitoring ---");

String rule = "entity.entityType == 'table' " +
"AND contains(entity.service.name, 'prod') " +
"AND (isEmpty(entity.description) OR length(entity.owners) == 0)";

DSLContext context = DSLContext.builder()
.entity(createMockEntity("orders", "table"))
.build();

boolean result = dsl.evaluateCondition(rule, context);
log.info("Rule: {}", rule);
log.info("Result: {}", result);
log.info("");
}

private static void exampleComplianceCheck(OpenMetadataDSL dsl) {
log.info("--- Example 3: Compliance & Governance ---");

String rule = "contains(entity.name, 'customer') " +
"AND NOT hasTag('GDPR-Compliant') " +
"AND entity.entityType == 'table'";

DSLContext context = DSLContext.builder()
.entity(createMockEntity("customer_data", "table"))
.build();

boolean result = dsl.evaluateCondition(rule, context);
log.info("Rule: {}", rule);
log.info("Result: {}", result);
log.info("");
}

private static void exampleSecurityMonitoring(OpenMetadataDSL dsl) {
log.info("--- Example 4: Security Monitoring ---");

String rule = "contains(entity.name, 'ssn') " +
"AND NOT hasTag('Security-Classified') " +
"AND entity.entityType == 'table'";

DSLContext context = DSLContext.builder()
.entity(createMockEntity("employee_ssn", "table"))
.build();

boolean result = dsl.evaluateCondition(rule, context);
log.info("Rule: {}", rule);
log.info("Result: {}", result);
log.info("");
}

private static EntityInterface createMockEntity(String name, String type) {
return new EntityInterface() {
@Override
public String getName() {
return name;
}

@Override
public String getFullyQualifiedName() {
return "prod." + name;
}

@Override
public String getDescription() {
return null;
}

@Override
public org.openmetadata.schema.type.EntityReference getEntityReference() {
return org.openmetadata.schema.type.EntityReference.builder()
.id(java.util.UUID.randomUUID())
.name(name)
.type(type)
.build();
}

@Override
public org.openmetadata.schema.type.EntityReference getService() {
return org.openmetadata.schema.type.EntityReference.builder()
.name("prod_mysql")
.type("databaseService")
.build();
}

@Override
public java.util.List<org.openmetadata.schema.type.TagLabel> getTags() {
return java.util.List.of(
org.openmetadata.schema.type.TagLabel.builder()
.tagFQN("Business-Critical")
.build()
);
}

@Override
public java.util.List<org.openmetadata.schema.type.EntityReference> getOwners() {
return null;
}

@Override
public Long getUpdatedAt() {
return System.currentTimeMillis();
}

@Override
public String getId() {
return java.util.UUID.randomUUID().toString();
}

@Override
public org.openmetadata.schema.type.EntityStatus getStatus() {
return org.openmetadata.schema.type.EntityStatus.ACTIVE;
}

@Override
public org.openmetadata.schema.type.Include getInclude() {
return org.openmetadata.schema.type.Include.ALL;
}

@Override
public java.util.Map<String, Object> getExtension() {
return null;
}

@Override
public void setExtension(java.util.Map<String, Object> extension) {}

@Override
public org.openmetadata.schema.type.ChangeDescription getChangeDescription() {
return null;
}

@Override
public void setChangeDescription(org.openmetadata.schema.type.ChangeDescription changeDescription) {}

@Override
public org.openmetadata.schema.type.Domain getDomain() {
return null;
}

@Override
public void setDomain(org.openmetadata.schema.type.Domain domain) {}

@Override
public java.util.List<org.openmetadata.schema.type.DataProduct> getDataProducts() {
return null;
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright 2026 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
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
Comment thread
gitar-bot[bot] marked this conversation as resolved.
package org.openmetadata.dsl;

import java.util.ArrayList;
import java.util.List;
import lombok.Builder;
import lombok.Data;

/**
* Represents a parsed DSL expression node.
*/
@Data
@Builder
public class DSLExpression {

public enum ExpressionType {
BOOLEAN,
NUMBER,
STRING,
FIELD,
FUNCTION,
BINARY_EXPR,
VARIABLE,
CONDITIONAL
}

private ExpressionType type;
private Boolean booleanValue;
private Number numberValue;
private String stringValue;
private String fieldName;
private String functionName;
private List<DSLExpression> arguments;
private DSLExpression left;
private DSLExpression right;
private String operator;
}
Loading
Loading