Bring back entitycertification and glosarystatus task for backward compatibility

This commit is contained in:
Ram Narayan Balaji 2025-09-22 22:09:54 +05:30
parent 284133979d
commit 28b566110e
8 changed files with 554 additions and 0 deletions

View File

@ -9,6 +9,8 @@ import org.openmetadata.schema.governance.workflows.elements.nodes.automatedTask
import org.openmetadata.schema.governance.workflows.elements.nodes.automatedTask.RollbackEntityTaskDefinition;
import org.openmetadata.schema.governance.workflows.elements.nodes.automatedTask.RunAppTaskDefinition;
import org.openmetadata.schema.governance.workflows.elements.nodes.automatedTask.SetEntityAttributeTaskDefinition;
import org.openmetadata.schema.governance.workflows.elements.nodes.automatedTask.SetEntityCertificationTaskDefinition;
import org.openmetadata.schema.governance.workflows.elements.nodes.automatedTask.SetGlossaryTermStatusTaskDefinition;
import org.openmetadata.schema.governance.workflows.elements.nodes.endEvent.EndEventDefinition;
import org.openmetadata.schema.governance.workflows.elements.nodes.gateway.ParallelGatewayDefinition;
import org.openmetadata.schema.governance.workflows.elements.nodes.startEvent.StartEventDefinition;
@ -17,6 +19,8 @@ import org.openmetadata.service.governance.workflows.elements.nodes.automatedTas
import org.openmetadata.service.governance.workflows.elements.nodes.automatedTask.DataCompletenessTask;
import org.openmetadata.service.governance.workflows.elements.nodes.automatedTask.RollbackEntityTask;
import org.openmetadata.service.governance.workflows.elements.nodes.automatedTask.SetEntityAttributeTask;
import org.openmetadata.service.governance.workflows.elements.nodes.automatedTask.SetEntityCertificationTask;
import org.openmetadata.service.governance.workflows.elements.nodes.automatedTask.SetGlossaryTermStatusTask;
import org.openmetadata.service.governance.workflows.elements.nodes.automatedTask.createAndRunIngestionPipeline.CreateAndRunIngestionPipelineTask;
import org.openmetadata.service.governance.workflows.elements.nodes.automatedTask.runApp.RunAppTask;
import org.openmetadata.service.governance.workflows.elements.nodes.endEvent.EndEvent;
@ -34,6 +38,10 @@ public class NodeFactory {
(CheckEntityAttributesTaskDefinition) nodeDefinition, config);
case SET_ENTITY_ATTRIBUTE_TASK -> new SetEntityAttributeTask(
(SetEntityAttributeTaskDefinition) nodeDefinition, config);
case SET_ENTITY_CERTIFICATION_TASK -> new SetEntityCertificationTask(
(SetEntityCertificationTaskDefinition) nodeDefinition, config);
case SET_GLOSSARY_TERM_STATUS_TASK -> new SetGlossaryTermStatusTask(
(SetGlossaryTermStatusTaskDefinition) nodeDefinition, config);
case USER_APPROVAL_TASK -> new UserApprovalTask(
(UserApprovalTaskDefinition) nodeDefinition, config);
case CREATE_AND_RUN_INGESTION_PIPELINE_TASK -> new CreateAndRunIngestionPipelineTask(

View File

@ -0,0 +1,102 @@
package org.openmetadata.service.governance.workflows.elements.nodes.automatedTask;
import static org.openmetadata.service.governance.workflows.Workflow.getFlowableElementId;
import java.util.Optional;
import org.flowable.bpmn.model.BoundaryEvent;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.EndEvent;
import org.flowable.bpmn.model.FieldExtension;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.SequenceFlow;
import org.flowable.bpmn.model.ServiceTask;
import org.flowable.bpmn.model.StartEvent;
import org.flowable.bpmn.model.SubProcess;
import org.openmetadata.schema.governance.workflows.WorkflowConfiguration;
import org.openmetadata.schema.governance.workflows.elements.nodes.automatedTask.CertificationConfiguration;
import org.openmetadata.schema.governance.workflows.elements.nodes.automatedTask.SetEntityCertificationTaskDefinition;
import org.openmetadata.schema.utils.JsonUtils;
import org.openmetadata.service.governance.workflows.elements.NodeInterface;
import org.openmetadata.service.governance.workflows.elements.nodes.automatedTask.impl.SetEntityCertificationImpl;
import org.openmetadata.service.governance.workflows.flowable.builders.EndEventBuilder;
import org.openmetadata.service.governance.workflows.flowable.builders.FieldExtensionBuilder;
import org.openmetadata.service.governance.workflows.flowable.builders.ServiceTaskBuilder;
import org.openmetadata.service.governance.workflows.flowable.builders.StartEventBuilder;
import org.openmetadata.service.governance.workflows.flowable.builders.SubProcessBuilder;
@Deprecated
public class SetEntityCertificationTask implements NodeInterface {
private final SubProcess subProcess;
private final BoundaryEvent runtimeExceptionBoundaryEvent;
public SetEntityCertificationTask(
SetEntityCertificationTaskDefinition nodeDefinition, WorkflowConfiguration config) {
String subProcessId = nodeDefinition.getName();
SubProcess subProcess = new SubProcessBuilder().id(subProcessId).build();
StartEvent startEvent =
new StartEventBuilder().id(getFlowableElementId(subProcessId, "startEvent")).build();
ServiceTask setEntityCertification =
getSetEntityCertificationServiceTask(
subProcessId,
(CertificationConfiguration.CertificationEnum)
nodeDefinition.getConfig().getCertification(),
JsonUtils.pojoToJson(nodeDefinition.getInputNamespaceMap()));
EndEvent endEvent =
new EndEventBuilder().id(getFlowableElementId(subProcessId, "endEvent")).build();
subProcess.addFlowElement(startEvent);
subProcess.addFlowElement(setEntityCertification);
subProcess.addFlowElement(endEvent);
subProcess.addFlowElement(new SequenceFlow(startEvent.getId(), setEntityCertification.getId()));
subProcess.addFlowElement(new SequenceFlow(setEntityCertification.getId(), endEvent.getId()));
if (config.getStoreStageStatus()) {
attachWorkflowInstanceStageListeners(subProcess);
}
this.runtimeExceptionBoundaryEvent =
getRuntimeExceptionBoundaryEvent(subProcess, config.getStoreStageStatus());
this.subProcess = subProcess;
}
@Override
public BoundaryEvent getRuntimeExceptionBoundaryEvent() {
return runtimeExceptionBoundaryEvent;
}
private ServiceTask getSetEntityCertificationServiceTask(
String subProcessId,
CertificationConfiguration.CertificationEnum certification,
String inputNamespaceMap) {
FieldExtension certificationExpr =
new FieldExtensionBuilder()
.fieldName("certificationExpr")
.fieldValue(
Optional.ofNullable(certification)
.map(CertificationConfiguration.CertificationEnum::value)
.orElse(""))
.build();
FieldExtension inputNamespaceMapExpr =
new FieldExtensionBuilder()
.fieldName("inputNamespaceMapExpr")
.fieldValue(inputNamespaceMap)
.build();
return new ServiceTaskBuilder()
.id(getFlowableElementId(subProcessId, "setGlossaryTermStatus"))
.implementation(SetEntityCertificationImpl.class.getName())
.addFieldExtension(certificationExpr)
.addFieldExtension(inputNamespaceMapExpr)
.build();
}
public void addToWorkflow(BpmnModel model, Process process) {
process.addFlowElement(subProcess);
process.addFlowElement(runtimeExceptionBoundaryEvent);
}
}

View File

@ -0,0 +1,91 @@
package org.openmetadata.service.governance.workflows.elements.nodes.automatedTask;
import static org.openmetadata.service.governance.workflows.Workflow.getFlowableElementId;
import org.flowable.bpmn.model.BoundaryEvent;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.EndEvent;
import org.flowable.bpmn.model.FieldExtension;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.SequenceFlow;
import org.flowable.bpmn.model.ServiceTask;
import org.flowable.bpmn.model.StartEvent;
import org.flowable.bpmn.model.SubProcess;
import org.openmetadata.schema.governance.workflows.WorkflowConfiguration;
import org.openmetadata.schema.governance.workflows.elements.nodes.automatedTask.SetGlossaryTermStatusTaskDefinition;
import org.openmetadata.schema.utils.JsonUtils;
import org.openmetadata.service.governance.workflows.elements.NodeInterface;
import org.openmetadata.service.governance.workflows.elements.nodes.automatedTask.impl.SetGlossaryTermStatusImpl;
import org.openmetadata.service.governance.workflows.flowable.builders.EndEventBuilder;
import org.openmetadata.service.governance.workflows.flowable.builders.FieldExtensionBuilder;
import org.openmetadata.service.governance.workflows.flowable.builders.ServiceTaskBuilder;
import org.openmetadata.service.governance.workflows.flowable.builders.StartEventBuilder;
import org.openmetadata.service.governance.workflows.flowable.builders.SubProcessBuilder;
@Deprecated
public class SetGlossaryTermStatusTask implements NodeInterface {
private final SubProcess subProcess;
private final BoundaryEvent runtimeExceptionBoundaryEvent;
public SetGlossaryTermStatusTask(
SetGlossaryTermStatusTaskDefinition nodeDefinition, WorkflowConfiguration config) {
String subProcessId = nodeDefinition.getName();
SubProcess subProcess = new SubProcessBuilder().id(subProcessId).build();
StartEvent startEvent =
new StartEventBuilder().id(getFlowableElementId(subProcessId, "startEvent")).build();
ServiceTask setGlossaryTermStatus =
getSetGlossaryTermStatusServiceTask(
subProcessId,
nodeDefinition.getConfig().getGlossaryTermStatus().toString(),
JsonUtils.pojoToJson(nodeDefinition.getInputNamespaceMap()));
EndEvent endEvent =
new EndEventBuilder().id(getFlowableElementId(subProcessId, "endEvent")).build();
subProcess.addFlowElement(startEvent);
subProcess.addFlowElement(setGlossaryTermStatus);
subProcess.addFlowElement(endEvent);
subProcess.addFlowElement(new SequenceFlow(startEvent.getId(), setGlossaryTermStatus.getId()));
subProcess.addFlowElement(new SequenceFlow(setGlossaryTermStatus.getId(), endEvent.getId()));
if (config.getStoreStageStatus()) {
attachWorkflowInstanceStageListeners(subProcess);
}
this.runtimeExceptionBoundaryEvent =
getRuntimeExceptionBoundaryEvent(subProcess, config.getStoreStageStatus());
this.subProcess = subProcess;
}
@Override
public BoundaryEvent getRuntimeExceptionBoundaryEvent() {
return runtimeExceptionBoundaryEvent;
}
private ServiceTask getSetGlossaryTermStatusServiceTask(
String subProcessId, String status, String inputNamespaceMap) {
FieldExtension statusExpr =
new FieldExtensionBuilder().fieldName("statusExpr").fieldValue(status).build();
FieldExtension inputNamespaceMapExpr =
new FieldExtensionBuilder()
.fieldName("inputNamespaceMapExpr")
.fieldValue(inputNamespaceMap)
.build();
return new ServiceTaskBuilder()
.id(getFlowableElementId(subProcessId, "setGlossaryTermStatus"))
.implementation(SetGlossaryTermStatusImpl.class.getName())
.addFieldExtension(statusExpr)
.addFieldExtension(inputNamespaceMapExpr)
.build();
}
public void addToWorkflow(BpmnModel model, Process process) {
process.addFlowElement(subProcess);
process.addFlowElement(runtimeExceptionBoundaryEvent);
}
}

View File

@ -0,0 +1,107 @@
package org.openmetadata.service.governance.workflows.elements.nodes.automatedTask.impl;
import static org.openmetadata.service.governance.workflows.Workflow.EXCEPTION_VARIABLE;
import static org.openmetadata.service.governance.workflows.Workflow.RELATED_ENTITY_VARIABLE;
import static org.openmetadata.service.governance.workflows.Workflow.UPDATED_BY_VARIABLE;
import static org.openmetadata.service.governance.workflows.Workflow.WORKFLOW_RUNTIME_EXCEPTION;
import static org.openmetadata.service.governance.workflows.WorkflowHandler.getProcessDefinitionKeyFromId;
import jakarta.json.JsonPatch;
import java.util.Map;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.flowable.common.engine.api.delegate.Expression;
import org.flowable.engine.delegate.BpmnError;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;
import org.openmetadata.schema.EntityInterface;
import org.openmetadata.schema.type.AssetCertification;
import org.openmetadata.schema.type.Include;
import org.openmetadata.schema.type.TagLabel;
import org.openmetadata.schema.utils.JsonUtils;
import org.openmetadata.service.Entity;
import org.openmetadata.service.governance.workflows.WorkflowVariableHandler;
import org.openmetadata.service.jdbi3.EntityRepository;
import org.openmetadata.service.resources.feeds.MessageParser;
@Deprecated
@Slf4j
public class SetEntityCertificationImpl implements JavaDelegate {
private Expression certificationExpr;
private Expression inputNamespaceMapExpr;
@Override
public void execute(DelegateExecution execution) {
WorkflowVariableHandler varHandler = new WorkflowVariableHandler(execution);
try {
Map<String, String> inputNamespaceMap =
JsonUtils.readOrConvertValue(inputNamespaceMapExpr.getValue(execution), Map.class);
MessageParser.EntityLink entityLink =
MessageParser.EntityLink.parse(
(String)
varHandler.getNamespacedVariable(
inputNamespaceMap.get(RELATED_ENTITY_VARIABLE), RELATED_ENTITY_VARIABLE));
String entityType = entityLink.getEntityType();
EntityInterface entity = Entity.getEntity(entityLink, "*", Include.ALL);
String certification =
Optional.ofNullable(certificationExpr)
.map(certificationExpr -> (String) certificationExpr.getValue(execution))
.orElse(null);
String user =
Optional.ofNullable(
(String)
varHandler.getNamespacedVariable(
inputNamespaceMap.get(UPDATED_BY_VARIABLE), UPDATED_BY_VARIABLE))
.orElse("governance-bot");
setStatus(entity, entityType, user, certification);
} catch (Exception exc) {
LOG.error(
String.format(
"[%s] Failure: ", getProcessDefinitionKeyFromId(execution.getProcessDefinitionId())),
exc);
varHandler.setGlobalVariable(EXCEPTION_VARIABLE, ExceptionUtils.getStackTrace(exc));
throw new BpmnError(WORKFLOW_RUNTIME_EXCEPTION, exc.getMessage());
}
}
private void setStatus(
EntityInterface entity, String entityType, String user, String certification) {
String originalJson = JsonUtils.pojoToJson(entity);
Optional<String> oCertification = Optional.ofNullable(certification);
Optional<AssetCertification> oEntityCertification =
Optional.ofNullable(entity.getCertification());
if (oCertification.isEmpty() && oEntityCertification.isEmpty()) {
return;
}
if (oCertification.isEmpty()) {
entity.setCertification(null);
} else {
if (oEntityCertification.isPresent()
&& oCertification.get().equals(oEntityCertification.get().getTagLabel().getTagFQN())) {
return;
}
AssetCertification assetCertification =
new AssetCertification()
.withTagLabel(
new TagLabel()
.withTagFQN(certification)
.withSource(TagLabel.TagSource.CLASSIFICATION)
.withLabelType(TagLabel.LabelType.AUTOMATED)
.withState(TagLabel.State.CONFIRMED));
entity.setCertification(assetCertification);
}
String updatedJson = JsonUtils.pojoToJson(entity);
JsonPatch patch = JsonUtils.getJsonPatch(originalJson, updatedJson);
EntityRepository<?> entityRepository = Entity.getEntityRepository(entityType);
entityRepository.patch(null, entity.getId(), user, patch);
}
}

View File

@ -0,0 +1,80 @@
package org.openmetadata.service.governance.workflows.elements.nodes.automatedTask.impl;
import static org.openmetadata.service.governance.workflows.Workflow.EXCEPTION_VARIABLE;
import static org.openmetadata.service.governance.workflows.Workflow.RELATED_ENTITY_VARIABLE;
import static org.openmetadata.service.governance.workflows.Workflow.UPDATED_BY_VARIABLE;
import static org.openmetadata.service.governance.workflows.Workflow.WORKFLOW_RUNTIME_EXCEPTION;
import static org.openmetadata.service.governance.workflows.WorkflowHandler.getProcessDefinitionKeyFromId;
import jakarta.json.JsonPatch;
import java.util.Map;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.flowable.common.engine.api.delegate.Expression;
import org.flowable.engine.delegate.BpmnError;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;
import org.openmetadata.schema.entity.data.GlossaryTerm;
import org.openmetadata.schema.type.EntityStatus;
import org.openmetadata.schema.type.Include;
import org.openmetadata.schema.utils.JsonUtils;
import org.openmetadata.service.Entity;
import org.openmetadata.service.governance.workflows.WorkflowVariableHandler;
import org.openmetadata.service.jdbi3.GlossaryTermRepository;
import org.openmetadata.service.resources.feeds.MessageParser;
@Deprecated
@Slf4j
public class SetGlossaryTermStatusImpl implements JavaDelegate {
private Expression statusExpr;
private Expression inputNamespaceMapExpr;
@Override
public void execute(DelegateExecution execution) {
WorkflowVariableHandler varHandler = new WorkflowVariableHandler(execution);
try {
Map<String, String> inputNamespaceMap =
JsonUtils.readOrConvertValue(inputNamespaceMapExpr.getValue(execution), Map.class);
MessageParser.EntityLink entityLink =
MessageParser.EntityLink.parse(
(String)
varHandler.getNamespacedVariable(
inputNamespaceMap.get(RELATED_ENTITY_VARIABLE), RELATED_ENTITY_VARIABLE));
GlossaryTerm glossaryTerm = Entity.getEntity(entityLink, "*", Include.ALL);
String status = (String) statusExpr.getValue(execution);
String user =
Optional.ofNullable(
(String)
varHandler.getNamespacedVariable(
inputNamespaceMap.get(UPDATED_BY_VARIABLE), UPDATED_BY_VARIABLE))
.orElse("governance-bot");
setStatus(glossaryTerm, user, status);
} catch (Exception exc) {
LOG.error(
String.format(
"[%s] Failure: ", getProcessDefinitionKeyFromId(execution.getProcessDefinitionId())),
exc);
varHandler.setGlobalVariable(EXCEPTION_VARIABLE, ExceptionUtils.getStackTrace(exc));
throw new BpmnError(WORKFLOW_RUNTIME_EXCEPTION, exc.getMessage());
}
}
private void setStatus(GlossaryTerm glossaryTerm, String user, String status) {
EntityStatus newStatus = EntityStatus.fromValue(status);
if (newStatus != glossaryTerm.getEntityStatus()) {
String originalJson = JsonUtils.pojoToJson(glossaryTerm);
glossaryTerm.setEntityStatus(newStatus);
String updatedJson = JsonUtils.pojoToJson(glossaryTerm);
JsonPatch patch = JsonUtils.getJsonPatch(originalJson, updatedJson);
GlossaryTermRepository entityRepository =
(GlossaryTermRepository) Entity.getEntityRepository(Entity.GLOSSARY_TERM);
entityRepository.patch(null, glossaryTerm.getId(), user, patch);
}
}
}

View File

@ -9,6 +9,8 @@
"userApprovalTask",
"checkEntityAttributesTask",
"setEntityAttributeTask",
"setEntityCertificationTask",
"setGlossaryTermStatusTask",
"endEvent",
"startEvent",
"createAndRunIngestionPipelineTask",

View File

@ -0,0 +1,92 @@
{
"$id": "https://open-metadata.org/schema/governance/workflows/elements/nodes/automatedTask/setEntityCertificationTask.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "SetEntityCertificationTaskDefinition",
"description": "Sets the Entity Certification to the configured value.",
"javaInterfaces": [
"org.openmetadata.schema.governance.workflows.elements.WorkflowNodeDefinitionInterface"
],
"javaType": "org.openmetadata.schema.governance.workflows.elements.nodes.automatedTask.SetEntityCertificationTaskDefinition",
"type": "object",
"definitions": {
"certificationEnum": {
"type": "string",
"enum": [
"",
"Certification.Gold",
"Certification.Silver",
"Certification.Bronze"
],
"enumNames": [
"None",
"Gold",
"Silver",
"Bronze"
]
},
"certificationConfiguration": {
"title": "Node Configuration",
"type": "object",
"properties": {
"certification": {
"title": "Certification",
"description": "Choose which Certification to apply to the Data Asset",
"$ref": "#/definitions/certificationEnum"
}
},
"required": ["certification"],
"additionalProperties": false
}
},
"properties": {
"type": {
"type": "string",
"default": "automatedTask"
},
"subType": {
"type": "string",
"default": "setEntityCertificationTask"
},
"name": {
"title": "Name",
"description": "Name that identifies this Node.",
"$ref": "../../../../../type/basic.json#/definitions/entityName"
},
"displayName": {
"title": "Display Name",
"description": "Display Name that identifies this Node.",
"type": "string"
},
"description": {
"title": "Description",
"description": "Description of the Node.",
"$ref": "../../../../../type/basic.json#/definitions/markdown"
},
"config": {
"$ref": "#/definitions/certificationConfiguration"
},
"input": {
"type": "array",
"items": { "type": "string" },
"default": ["relatedEntity", "updatedBy"],
"additionalItems": false,
"minItems": 2,
"maxItems": 2
},
"inputNamespaceMap": {
"type": "object",
"properties": {
"relatedEntity": {
"type": "string",
"default": "global"
},
"updatedBy": {
"type": "string",
"default": null
}
},
"additionalProperties": false,
"required": ["relatedEntity"]
}
}
}

View File

@ -0,0 +1,72 @@
{
"$id": "https://open-metadata.org/schema/governance/workflows/elements/nodes/automatedTask/setGlossaryTermStatusTask.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "SetGlossaryTermStatusTaskDefinition",
"description": "Sets the GlossaryTerm Status to the configured value.",
"javaInterfaces": [
"org.openmetadata.schema.governance.workflows.elements.WorkflowNodeDefinitionInterface"
],
"javaType": "org.openmetadata.schema.governance.workflows.elements.nodes.automatedTask.SetGlossaryTermStatusTaskDefinition",
"type": "object",
"properties": {
"type": {
"type": "string",
"default": "automatedTask"
},
"subType": {
"type": "string",
"default": "setGlossaryTermStatusTask"
},
"name": {
"title": "Name",
"description": "Name that identifies this Node.",
"$ref": "../../../../../type/basic.json#/definitions/entityName"
},
"displayName": {
"title": "Display Name",
"description": "Display Name that identifies this Node.",
"type": "string"
},
"description": {
"title": "Description",
"description": "Description of the Node.",
"$ref": "../../../../../type/basic.json#/definitions/markdown"
},
"config": {
"title": "Node Configuration",
"type": "object",
"properties": {
"glossaryTermStatus": {
"title": "Glossary Term Status",
"description": "Choose which Status to apply to the Glossary Term",
"$ref": "../../../../../type/status.json"
}
},
"required": ["glossaryTermStatus"],
"additionalProperties": false
},
"input": {
"type": "array",
"items": { "type": "string" },
"default": ["relatedEntity", "updatedBy"],
"additionalItems": false,
"minItems": 2,
"maxItems": 2
},
"inputNamespaceMap": {
"type": "object",
"properties": {
"relatedEntity": {
"type": "string",
"default": "global"
},
"updatedBy": {
"type": "string",
"default": null
}
},
"additionalProperties": false,
"required": ["relatedEntity"]
}
}
}