diff --git a/open-metadata-implementation/access-services/data-engine/data-engine-api/src/main/java/org/odpi/openmetadata/accessservices/dataengine/ffdc/DataEngineErrorCode.java b/open-metadata-implementation/access-services/data-engine/data-engine-api/src/main/java/org/odpi/openmetadata/accessservices/dataengine/ffdc/DataEngineErrorCode.java index 0b57469b384..706e99fd03c 100644 --- a/open-metadata-implementation/access-services/data-engine/data-engine-api/src/main/java/org/odpi/openmetadata/accessservices/dataengine/ffdc/DataEngineErrorCode.java +++ b/open-metadata-implementation/access-services/data-engine/data-engine-api/src/main/java/org/odpi/openmetadata/accessservices/dataengine/ffdc/DataEngineErrorCode.java @@ -84,7 +84,11 @@ public enum DataEngineErrorCode implements ExceptionMessageSet { TOPIC_NOT_FOUND(400, "OMAS-DATA-ENGINE-400-011", "Topic with qualifiedName {0} was not found", "The system is unable to create a new event type attached to a topic", - "Correct the code in the caller to provide the correct topic qualified name."); + "Correct the code in the caller to provide the correct topic qualified name."), + SOFTWARE_SERVER_CAPABILITY_NOT_FOUND(400, "OMAS-DATA-ENGINE-400-012", + "Software Server Capability with qualifiedName {0} was not found", + "The system is unable to find the searched Software Server Capability", + "Correct the code in the caller to provide the correct Software Server Capability qualified name."); private static final long serialVersionUID = 1L; diff --git a/open-metadata-implementation/access-services/data-engine/data-engine-api/src/main/java/org/odpi/openmetadata/accessservices/dataengine/model/ProcessingState.java b/open-metadata-implementation/access-services/data-engine/data-engine-api/src/main/java/org/odpi/openmetadata/accessservices/dataengine/model/ProcessingState.java new file mode 100644 index 00000000000..fac72fcae7f --- /dev/null +++ b/open-metadata-implementation/access-services/data-engine/data-engine-api/src/main/java/org/odpi/openmetadata/accessservices/dataengine/model/ProcessingState.java @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright Contributors to the ODPi Egeria project. */ +package org.odpi.openmetadata.accessservices.dataengine.model; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +import java.util.Map; + +import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE; +import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.PUBLIC_ONLY; + +/** + * The ProcessingState classification + */ +@JsonAutoDetect(getterVisibility = PUBLIC_ONLY, setterVisibility = PUBLIC_ONLY, fieldVisibility = NONE) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Getter +@Setter +public class ProcessingState extends Referenceable { + + @Getter(AccessLevel.NONE) + @Setter(AccessLevel.NONE) + private static final long serialVersionUID = 1L; + + /** + * The Sync Dates map of critical elements and sync status + * -- GETTER -- + * Gets sync states map. + * + * @return sync states map + * -- SETTER -- + * Sets sync states map. + * @param syncDatesByKey the sync states map + */ + @JsonProperty("syncDatesByKey") + private Map syncDatesByKey; +} diff --git a/open-metadata-implementation/access-services/data-engine/data-engine-api/src/main/java/org/odpi/openmetadata/accessservices/dataengine/rest/ProcessingStateRequestBody.java b/open-metadata-implementation/access-services/data-engine/data-engine-api/src/main/java/org/odpi/openmetadata/accessservices/dataengine/rest/ProcessingStateRequestBody.java new file mode 100644 index 00000000000..9fb9c08a5c6 --- /dev/null +++ b/open-metadata-implementation/access-services/data-engine/data-engine-api/src/main/java/org/odpi/openmetadata/accessservices/dataengine/rest/ProcessingStateRequestBody.java @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright Contributors to the ODPi Egeria project. */ +package org.odpi.openmetadata.accessservices.dataengine.rest; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import org.odpi.openmetadata.accessservices.dataengine.model.ProcessingState; + +import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE; +import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.PUBLIC_ONLY; + +@JsonAutoDetect(getterVisibility = PUBLIC_ONLY, setterVisibility = PUBLIC_ONLY, fieldVisibility = NONE) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +@Getter +@Setter +@EqualsAndHashCode(callSuper = true) +@ToString +public class ProcessingStateRequestBody extends DataEngineOMASAPIRequestBody +{ + private static final long serialVersionUID = 1L; + + /** + * The sync state to be created + * -- GETTER -- + * Return the sync state bean + * + * @return the sync state + * -- SETTER -- + * Set up the sync state bean + * @param processingState the sync state + */ + @JsonProperty("processingState") + private ProcessingState processingState; +} + + + + + + diff --git a/open-metadata-implementation/access-services/data-engine/data-engine-server/src/main/java/org/odpi/openmetadata/accessservices/dataengine/server/handlers/DataEngineRegistrationHandler.java b/open-metadata-implementation/access-services/data-engine/data-engine-server/src/main/java/org/odpi/openmetadata/accessservices/dataengine/server/handlers/DataEngineRegistrationHandler.java index 38f9342f6a7..4e50f65631f 100644 --- a/open-metadata-implementation/access-services/data-engine/data-engine-server/src/main/java/org/odpi/openmetadata/accessservices/dataengine/server/handlers/DataEngineRegistrationHandler.java +++ b/open-metadata-implementation/access-services/data-engine/data-engine-server/src/main/java/org/odpi/openmetadata/accessservices/dataengine/server/handlers/DataEngineRegistrationHandler.java @@ -2,27 +2,37 @@ /* Copyright Contributors to the ODPi Egeria project. */ package org.odpi.openmetadata.accessservices.dataengine.server.handlers; +import org.odpi.openmetadata.accessservices.dataengine.ffdc.DataEngineErrorCode; import org.odpi.openmetadata.accessservices.dataengine.model.DeleteSemantic; +import org.odpi.openmetadata.accessservices.dataengine.model.ProcessingState; import org.odpi.openmetadata.accessservices.dataengine.model.SoftwareServerCapability; import org.odpi.openmetadata.accessservices.dataengine.server.builders.ExternalDataEnginePropertiesBuilder; import org.odpi.openmetadata.accessservices.dataengine.server.mappers.CommonMapper; import org.odpi.openmetadata.accessservices.dataengine.server.service.ClockService; import org.odpi.openmetadata.commonservices.ffdc.InvalidParameterHandler; import org.odpi.openmetadata.commonservices.generichandlers.SoftwareCapabilityHandler; +import org.odpi.openmetadata.frameworks.auditlog.messagesets.ExceptionMessageDefinition; import org.odpi.openmetadata.frameworks.connectors.ffdc.InvalidParameterException; import org.odpi.openmetadata.frameworks.connectors.ffdc.PropertyServerException; import org.odpi.openmetadata.frameworks.connectors.ffdc.UserNotAuthorizedException; +import org.odpi.openmetadata.repositoryservices.connectors.stores.metadatacollectionstore.properties.instances.Classification; import org.odpi.openmetadata.repositoryservices.connectors.stores.metadatacollectionstore.properties.instances.EntityDetail; import org.odpi.openmetadata.repositoryservices.connectors.stores.metadatacollectionstore.properties.instances.InstanceProperties; +import org.odpi.openmetadata.repositoryservices.connectors.stores.metadatacollectionstore.properties.instances.MapPropertyValue; +import org.odpi.openmetadata.repositoryservices.connectors.stores.metadatacollectionstore.properties.instances.PrimitivePropertyValue; import org.odpi.openmetadata.repositoryservices.connectors.stores.metadatacollectionstore.properties.typedefs.TypeDef; import org.odpi.openmetadata.repositoryservices.connectors.stores.metadatacollectionstore.repositoryconnector.OMRSRepositoryHelper; import org.odpi.openmetadata.repositoryservices.ffdc.OMRSErrorCode; import org.odpi.openmetadata.repositoryservices.ffdc.exception.FunctionNotSupportedException; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import static org.odpi.openmetadata.accessservices.dataengine.server.mappers.CommonMapper.GUID_PROPERTY_NAME; import static org.odpi.openmetadata.accessservices.dataengine.server.mappers.CommonMapper.QUALIFIED_NAME_PROPERTY_NAME; +import static org.odpi.openmetadata.commonservices.generichandlers.OpenMetadataAPIMapper.PROCESSING_STATE_CLASSIFICATION_TYPE_GUID; +import static org.odpi.openmetadata.commonservices.generichandlers.OpenMetadataAPIMapper.PROCESSING_STATE_CLASSIFICATION_TYPE_NAME; import static org.odpi.openmetadata.commonservices.generichandlers.OpenMetadataAPIMapper.SOFTWARE_SERVER_CAPABILITY_TYPE_NAME; /** @@ -31,6 +41,9 @@ * SoftwareCapabilityHandler. */ public class DataEngineRegistrationHandler { + + private static final String EXTERNAL_ENGINE_PARAMETER_NAME = "externalSourceGUID"; + public static final String SYNC_DATES_BY_KEY = "syncDatesByKey"; private final String serviceName; private final String serverName; private final OMRSRepositoryHelper repositoryHelper; @@ -149,4 +162,64 @@ ExternalDataEnginePropertiesBuilder getExternalDataEnginePropertiesBuilder(Softw softwareServerCapability.getEngineVersion(), softwareServerCapability.getPatchLevel(), softwareServerCapability.getSource(), softwareServerCapability.getAdditionalProperties(), repositoryHelper, serviceName, serverName); } + + public void createDataEngineClassification(String userId, ProcessingState processingState, String externalSourceName) throws + InvalidParameterException, + UserNotAuthorizedException, + PropertyServerException { + final String methodName = "createDataEngineClassification"; + + invalidParameterHandler.validateUserId(userId, methodName); + + String externalSourceGUID = this.getExternalDataEngine(userId, externalSourceName); + if (externalSourceGUID == null) { + ExceptionMessageDefinition messageDefinition = DataEngineErrorCode.SOFTWARE_SERVER_CAPABILITY_NOT_FOUND.getMessageDefinition(externalSourceName); + throw new InvalidParameterException(messageDefinition, this.getClass().getName(), methodName, EXTERNAL_ENGINE_PARAMETER_NAME); + } + + //Check if the entity has this classification and if it does then merge the syncDatesByKey + + TypeDef entityTypeDef = repositoryHelper.getTypeDefByName(userId, SOFTWARE_SERVER_CAPABILITY_TYPE_NAME); + EntityDetail retrievedEntity = softwareServerCapabilityHandler.getEntityByValue(userId, externalSourceName, CommonMapper.QUALIFIED_NAME_PROPERTY_NAME, + entityTypeDef.getGUID(), entityTypeDef.getName(), Collections.singletonList(CommonMapper.QUALIFIED_NAME_PROPERTY_NAME), + false, false, null, methodName); + + Map newSyncDatesByKey = new HashMap<>(); + + if (retrievedEntity.getClassifications() != null) { + for (Classification classification : retrievedEntity.getClassifications()) { + if (classification != null && classification.getName().equals(PROCESSING_STATE_CLASSIFICATION_TYPE_NAME)) { + MapPropertyValue syncDatesByKey = (MapPropertyValue) classification.getProperties().getPropertyValue(SYNC_DATES_BY_KEY); + for (Map.Entry entry : syncDatesByKey.getMapValues().getInstanceProperties().entrySet()) { + newSyncDatesByKey.put(entry.getKey().toString(), + ((Long) ((PrimitivePropertyValue) entry.getValue()).getPrimitiveValue()).longValue()); + } + newSyncDatesByKey.putAll(processingState.getSyncDatesByKey()); + } + } + } + + if (newSyncDatesByKey.isEmpty()) { + newSyncDatesByKey = processingState.getSyncDatesByKey(); + } + + InstanceProperties instanceProperties = new InstanceProperties(); + instanceProperties = repositoryHelper.addLongMapPropertyToInstance(null, instanceProperties, SYNC_DATES_BY_KEY, + newSyncDatesByKey, methodName); + + softwareServerCapabilityHandler.setClassificationInRepository(userId, + null, + null, + externalSourceGUID, + EXTERNAL_ENGINE_PARAMETER_NAME, + SOFTWARE_SERVER_CAPABILITY_TYPE_NAME, + PROCESSING_STATE_CLASSIFICATION_TYPE_GUID, + PROCESSING_STATE_CLASSIFICATION_TYPE_NAME, + instanceProperties, + true, + false, + false, + null, + methodName); + } } \ No newline at end of file diff --git a/open-metadata-implementation/access-services/data-engine/data-engine-server/src/main/java/org/odpi/openmetadata/accessservices/dataengine/server/service/DataEngineRESTServices.java b/open-metadata-implementation/access-services/data-engine/data-engine-server/src/main/java/org/odpi/openmetadata/accessservices/dataengine/server/service/DataEngineRESTServices.java index 8e4403094a0..efa9392e0d1 100644 --- a/open-metadata-implementation/access-services/data-engine/data-engine-server/src/main/java/org/odpi/openmetadata/accessservices/dataengine/server/service/DataEngineRESTServices.java +++ b/open-metadata-implementation/access-services/data-engine/data-engine-server/src/main/java/org/odpi/openmetadata/accessservices/dataengine/server/service/DataEngineRESTServices.java @@ -20,6 +20,7 @@ import org.odpi.openmetadata.accessservices.dataengine.model.PortImplementation; import org.odpi.openmetadata.accessservices.dataengine.model.Process; import org.odpi.openmetadata.accessservices.dataengine.model.ProcessHierarchy; +import org.odpi.openmetadata.accessservices.dataengine.model.ProcessingState; import org.odpi.openmetadata.accessservices.dataengine.model.Referenceable; import org.odpi.openmetadata.accessservices.dataengine.model.RelationalTable; import org.odpi.openmetadata.accessservices.dataengine.model.SchemaType; @@ -39,6 +40,7 @@ import org.odpi.openmetadata.accessservices.dataengine.rest.PortImplementationRequestBody; import org.odpi.openmetadata.accessservices.dataengine.rest.ProcessHierarchyRequestBody; import org.odpi.openmetadata.accessservices.dataengine.rest.ProcessRequestBody; +import org.odpi.openmetadata.accessservices.dataengine.rest.ProcessingStateRequestBody; import org.odpi.openmetadata.accessservices.dataengine.rest.RelationalTableRequestBody; import org.odpi.openmetadata.accessservices.dataengine.rest.SchemaTypeRequestBody; import org.odpi.openmetadata.accessservices.dataengine.rest.TopicRequestBody; @@ -97,6 +99,7 @@ import static org.odpi.openmetadata.commonservices.generichandlers.OpenMetadataAPIMapper.PORT_ALIAS_TYPE_NAME; import static org.odpi.openmetadata.commonservices.generichandlers.OpenMetadataAPIMapper.PORT_IMPLEMENTATION_TYPE_NAME; import static org.odpi.openmetadata.commonservices.generichandlers.OpenMetadataAPIMapper.PORT_TYPE_NAME; +import static org.odpi.openmetadata.commonservices.generichandlers.OpenMetadataAPIMapper.PROCESSING_STATE_CLASSIFICATION_TYPE_NAME; import static org.odpi.openmetadata.commonservices.generichandlers.OpenMetadataAPIMapper.PROCESS_TYPE_NAME; import static org.odpi.openmetadata.commonservices.generichandlers.OpenMetadataAPIMapper.QUALIFIED_NAME_PROPERTY_NAME; import static org.odpi.openmetadata.commonservices.generichandlers.OpenMetadataAPIMapper.QUOTE_CHARACTER_PROPERTY_NAME; @@ -2172,6 +2175,55 @@ public void deleteEventType(String userId, String serverName, String externalSou log.debug(DEBUG_DELETE_MESSAGE, eventTypeGUID, TOPIC_TYPE_NAME); } + /** + * Create or update the ProcessingState with provided map of critical elements and sync states + * + * @param serverName name of server instance to call + * @param userId the name of the calling user + * @param processingStateRequestBody map of critical elements and sync states + * @return void response + */ + public VoidResponse upsertProcessingState(String userId, String serverName, ProcessingStateRequestBody processingStateRequestBody) { + final String methodName = "upsertProcessingState"; + + VoidResponse response = new VoidResponse(); + try { + validateRequestBody(userId, serverName, processingStateRequestBody, methodName); + + ProcessingState processingState = processingStateRequestBody.getProcessingState(); + if (processingState == null) { + restExceptionHandler.handleMissingValue("processingState", methodName); + return response; + } + return upsertProcessingState(userId, serverName, processingState, processingStateRequestBody.getExternalSourceName()); + } catch (Exception error) { + restExceptionHandler.captureExceptions(response, error, methodName); + } + return response; + } + + /** + * Create or update the ProcessingState with provided map of critical elements and sync states + * + * @param serverName name of server instance to call + * @param userId the name of the calling user + * @param processingState map of critical elements and sync states + * @param externalSourceName the unique name of the external source + * @return void response + */ + public VoidResponse upsertProcessingState(String userId, String serverName, ProcessingState processingState, String externalSourceName) { + final String methodName = "upsertProcessingState"; + + VoidResponse response = new VoidResponse(); + try { + DataEngineRegistrationHandler handler = instanceHandler.getRegistrationHandler(userId, serverName, methodName); + handler.createDataEngineClassification(userId, processingState, externalSourceName); + } catch (Exception error) { + restExceptionHandler.captureExceptions(response, error, methodName); + } + return response; + } + private boolean isTopicRequestBodyValid(String userId, String serverName, TopicRequestBody topicRequestBody, String methodName) throws InvalidParameterException { validateRequestBody(userId, serverName, topicRequestBody, methodName); diff --git a/open-metadata-implementation/access-services/data-engine/data-engine-server/src/test/java/org/odpi/openmetadata/accessservices/dataengine/server/handlers/DataEngineRegistrationHandlerTest.java b/open-metadata-implementation/access-services/data-engine/data-engine-server/src/test/java/org/odpi/openmetadata/accessservices/dataengine/server/handlers/DataEngineRegistrationHandlerTest.java index 6b6b6455f39..5c770f30aad 100644 --- a/open-metadata-implementation/access-services/data-engine/data-engine-server/src/test/java/org/odpi/openmetadata/accessservices/dataengine/server/handlers/DataEngineRegistrationHandlerTest.java +++ b/open-metadata-implementation/access-services/data-engine/data-engine-server/src/test/java/org/odpi/openmetadata/accessservices/dataengine/server/handlers/DataEngineRegistrationHandlerTest.java @@ -8,10 +8,12 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; +import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; import org.odpi.openmetadata.accessservices.dataengine.model.DeleteSemantic; +import org.odpi.openmetadata.accessservices.dataengine.model.ProcessingState; import org.odpi.openmetadata.accessservices.dataengine.model.SoftwareServerCapability; import org.odpi.openmetadata.accessservices.dataengine.server.builders.ExternalDataEnginePropertiesBuilder; import org.odpi.openmetadata.accessservices.dataengine.server.mappers.CommonMapper; @@ -22,8 +24,10 @@ import org.odpi.openmetadata.frameworks.connectors.ffdc.PropertyServerException; import org.odpi.openmetadata.frameworks.connectors.ffdc.UserNotAuthorizedException; import org.odpi.openmetadata.repositoryservices.connectors.stores.metadatacollectionstore.properties.instances.EntityDetail; +import org.odpi.openmetadata.repositoryservices.connectors.stores.metadatacollectionstore.properties.instances.InstanceProperties; import org.odpi.openmetadata.repositoryservices.connectors.stores.metadatacollectionstore.properties.typedefs.TypeDef; import org.odpi.openmetadata.repositoryservices.connectors.stores.metadatacollectionstore.repositoryconnector.OMRSRepositoryHelper; +import org.odpi.openmetadata.repositoryservices.ffdc.exception.EntityNotKnownException; import org.odpi.openmetadata.repositoryservices.ffdc.exception.FunctionNotSupportedException; import java.lang.reflect.InvocationTargetException; @@ -33,12 +37,17 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.odpi.openmetadata.accessservices.dataengine.server.mappers.CommonMapper.GUID_PROPERTY_NAME; +import static org.odpi.openmetadata.accessservices.dataengine.server.handlers.DataEngineRegistrationHandler.SYNC_DATES_BY_KEY; import static org.odpi.openmetadata.accessservices.dataengine.server.util.MockedExceptionUtil.mockException; +import static org.odpi.openmetadata.commonservices.generichandlers.OpenMetadataAPIMapper.GUID_PROPERTY_NAME; +import static org.odpi.openmetadata.commonservices.generichandlers.OpenMetadataAPIMapper.PROCESSING_STATE_CLASSIFICATION_TYPE_GUID; +import static org.odpi.openmetadata.commonservices.generichandlers.OpenMetadataAPIMapper.PROCESSING_STATE_CLASSIFICATION_TYPE_NAME; import static org.odpi.openmetadata.commonservices.generichandlers.OpenMetadataAPIMapper.QUALIFIED_NAME_PROPERTY_NAME; import static org.odpi.openmetadata.commonservices.generichandlers.OpenMetadataAPIMapper.SOFTWARE_SERVER_CAPABILITY_TYPE_GUID; import static org.odpi.openmetadata.commonservices.generichandlers.OpenMetadataAPIMapper.SOFTWARE_SERVER_CAPABILITY_TYPE_NAME; @@ -72,6 +81,7 @@ class DataEngineRegistrationHandlerTest { private ClockService clockService; @InjectMocks + @Spy private DataEngineRegistrationHandler registrationHandler; @BeforeEach @@ -213,6 +223,84 @@ private void mockEntityTypeDef() { when(entityTypeDef.getGUID()).thenReturn(SOFTWARE_SERVER_CAPABILITY_TYPE_GUID); } + @Test + void createDataEngineClassification() throws InvalidParameterException, PropertyServerException, UserNotAuthorizedException, EntityNotKnownException { + String methodName = "createDataEngineClassification"; + ProcessingState processingState = getProcessingState(); + InstanceProperties properties = new InstanceProperties(); + EntityDetail entityDetail = mock(EntityDetail.class); + + SoftwareServerCapability softwareServerCapability = getSoftwareServerCapability(); + + doReturn(GUID).when(registrationHandler).getExternalDataEngine(USER, + softwareServerCapability.getQualifiedName()); + + when(repositoryHelper.addLongMapPropertyToInstance(null, properties, SYNC_DATES_BY_KEY, + processingState.getSyncDatesByKey(), methodName)).thenReturn(properties); + + when(softwareServerCapabilityHandler.getEntityByValue(USER, QUALIFIED_NAME, CommonMapper.QUALIFIED_NAME_PROPERTY_NAME, + SOFTWARE_SERVER_CAPABILITY_TYPE_GUID, SOFTWARE_SERVER_CAPABILITY_TYPE_NAME, + Collections.singletonList(CommonMapper.QUALIFIED_NAME_PROPERTY_NAME), false, + false, null, methodName)).thenReturn(entityDetail); + + when(entityDetail.getClassifications()).thenReturn(null); + + doNothing().when(softwareServerCapabilityHandler).setClassificationInRepository(USER, null, + null, GUID, EXTERNAL_SOURCE_DE_GUID, SOFTWARE_SERVER_CAPABILITY_TYPE_NAME, PROCESSING_STATE_CLASSIFICATION_TYPE_GUID, + PROCESSING_STATE_CLASSIFICATION_TYPE_NAME, properties, true, false, false, + null, methodName); + + registrationHandler.createDataEngineClassification(USER, processingState, softwareServerCapability.getQualifiedName()); + + verify(invalidParameterHandler, times(1)).validateUserId(USER, methodName); + verify(repositoryHelper, times(1)).addLongMapPropertyToInstance(null, properties, + SYNC_DATES_BY_KEY, processingState.getSyncDatesByKey(), methodName); + verify(softwareServerCapabilityHandler, times(1)).setClassificationInRepository(USER, null, + null, GUID, EXTERNAL_SOURCE_DE_GUID, SOFTWARE_SERVER_CAPABILITY_TYPE_NAME, PROCESSING_STATE_CLASSIFICATION_TYPE_GUID, + PROCESSING_STATE_CLASSIFICATION_TYPE_NAME, properties, true, false, false, + null, methodName); + } + + @Test + void createDataEngineClassification_throwsUserNotAuthorizedException() throws UserNotAuthorizedException, + PropertyServerException, + InvocationTargetException, + NoSuchMethodException, + InstantiationException, + IllegalAccessException, InvalidParameterException { + String methodName = "createDataEngineClassification"; + ProcessingState processingState = getProcessingState(); + InstanceProperties properties = new InstanceProperties(); + EntityDetail entityDetail = mock(EntityDetail.class); + + SoftwareServerCapability softwareServerCapability = getSoftwareServerCapability(); + + doReturn(GUID).when(registrationHandler).getExternalDataEngine(USER, + softwareServerCapability.getQualifiedName()); + + when(softwareServerCapabilityHandler.getEntityByValue(USER, QUALIFIED_NAME, CommonMapper.QUALIFIED_NAME_PROPERTY_NAME, + SOFTWARE_SERVER_CAPABILITY_TYPE_GUID, SOFTWARE_SERVER_CAPABILITY_TYPE_NAME, + Collections.singletonList(CommonMapper.QUALIFIED_NAME_PROPERTY_NAME), false, + false, null, methodName)).thenReturn(entityDetail); + + when(entityDetail.getClassifications()).thenReturn(null); + + when(repositoryHelper.addLongMapPropertyToInstance(null, properties, SYNC_DATES_BY_KEY, + processingState.getSyncDatesByKey(), methodName)).thenReturn(properties); + + UserNotAuthorizedException mockedException = mockException(UserNotAuthorizedException.class, methodName); + doThrow(mockedException).when(softwareServerCapabilityHandler).setClassificationInRepository(USER, null, + null, GUID, EXTERNAL_SOURCE_DE_GUID, SOFTWARE_SERVER_CAPABILITY_TYPE_NAME, PROCESSING_STATE_CLASSIFICATION_TYPE_GUID, + PROCESSING_STATE_CLASSIFICATION_TYPE_NAME, properties, true, false, false, + null, methodName); + + UserNotAuthorizedException thrown = assertThrows(UserNotAuthorizedException.class, () -> + registrationHandler.createDataEngineClassification(USER, processingState, softwareServerCapability.getQualifiedName())); + + assertTrue(thrown.getMessage().contains("OMAS-DATA-ENGINE-404-001 ")); + } + + private SoftwareServerCapability getSoftwareServerCapability() { SoftwareServerCapability softwareServerCapability = new SoftwareServerCapability(); @@ -227,4 +315,10 @@ private SoftwareServerCapability getSoftwareServerCapability() { return softwareServerCapability; } + + private ProcessingState getProcessingState() { + ProcessingState processingState = new ProcessingState(); + processingState.setSyncDatesByKey(Collections.EMPTY_MAP); + return processingState; + } } \ No newline at end of file diff --git a/open-metadata-implementation/access-services/data-engine/data-engine-spring/src/main/java/org/odpi/openmetadata/accessservices/dataengine/server/spring/DataEngineResource.java b/open-metadata-implementation/access-services/data-engine/data-engine-spring/src/main/java/org/odpi/openmetadata/accessservices/dataengine/server/spring/DataEngineResource.java index 725997564c6..03e25faf2b1 100644 --- a/open-metadata-implementation/access-services/data-engine/data-engine-spring/src/main/java/org/odpi/openmetadata/accessservices/dataengine/server/spring/DataEngineResource.java +++ b/open-metadata-implementation/access-services/data-engine/data-engine-spring/src/main/java/org/odpi/openmetadata/accessservices/dataengine/server/spring/DataEngineResource.java @@ -16,6 +16,7 @@ import org.odpi.openmetadata.accessservices.dataengine.rest.PortImplementationRequestBody; import org.odpi.openmetadata.accessservices.dataengine.rest.ProcessHierarchyRequestBody; import org.odpi.openmetadata.accessservices.dataengine.rest.ProcessRequestBody; +import org.odpi.openmetadata.accessservices.dataengine.rest.ProcessingStateRequestBody; import org.odpi.openmetadata.accessservices.dataengine.rest.RelationalTableRequestBody; import org.odpi.openmetadata.accessservices.dataengine.rest.SchemaTypeRequestBody; import org.odpi.openmetadata.accessservices.dataengine.rest.TopicRequestBody; @@ -541,4 +542,20 @@ public VoidResponse deleteEventType(@PathVariable("userId") String userId, @RequestBody DeleteRequestBody requestBody) { return restAPI.deleteEventType(userId, serverName, requestBody); } + + /** + * Create or update a processing state entity with the provided properties + * + * @param serverName name of server instance to call + * @param userId the name of the calling user + * @param requestBody properties of the processing state + * @return void response + */ + @PostMapping(path = "/processing-state") + public VoidResponse upsertProcessingState(@PathVariable("userId") String userId, + @PathVariable("serverName") String serverName, + @RequestBody ProcessingStateRequestBody requestBody) { + return restAPI.upsertProcessingState(userId, serverName, requestBody); + } + } diff --git a/open-metadata-implementation/access-services/data-engine/docs/samples/collections/DataEngine-asset_endpoints.postman_collection.json b/open-metadata-implementation/access-services/data-engine/docs/samples/collections/DataEngine-asset_endpoints.postman_collection.json index a12dd2827f9..7ad041fbf0d 100644 --- a/open-metadata-implementation/access-services/data-engine/docs/samples/collections/DataEngine-asset_endpoints.postman_collection.json +++ b/open-metadata-implementation/access-services/data-engine/docs/samples/collections/DataEngine-asset_endpoints.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "582b2a6f-c942-4bdf-b527-fb789bb13d19", + "_postman_id": "8099fb01-9085-42ff-8560-049eb7c9a8d4", "name": "DataEngine - asset endpoints", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, @@ -3222,6 +3222,66 @@ } }, "response": [] + }, + { + "name": "10.1 Upsert Processing State Classification", + "request": { + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "demo", + "type": "string" + }, + { + "key": "password", + "value": "demo", + "type": "string" + }, + { + "key": "showPassword", + "value": false, + "type": "boolean" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"externalSourceName\": \"(organization)=Company::(project)=ExternalDataPlatform\",\n \"processingState\": {\n \"syncDatesByKey\" : {\n \"{{criticalElement}}\" : \"{{criticalElementLastSyncTimestampLong}}\"\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base-url}}/servers/{{server-id}}/open-metadata/access-services/data-engine/users/{{user-id}}/processing-state", + "host": [ + "{{base-url}}" + ], + "path": [ + "servers", + "{{server-id}}", + "open-metadata", + "access-services", + "data-engine", + "users", + "{{user-id}}", + "processing-state" + ] + } + }, + "response": [] } ] } \ No newline at end of file diff --git a/open-metadata-implementation/common-services/generic-handlers/src/main/java/org/odpi/openmetadata/commonservices/generichandlers/OpenMetadataAPIMapper.java b/open-metadata-implementation/common-services/generic-handlers/src/main/java/org/odpi/openmetadata/commonservices/generichandlers/OpenMetadataAPIMapper.java index 56c5bc59661..12a9dfe6e19 100644 --- a/open-metadata-implementation/common-services/generic-handlers/src/main/java/org/odpi/openmetadata/commonservices/generichandlers/OpenMetadataAPIMapper.java +++ b/open-metadata-implementation/common-services/generic-handlers/src/main/java/org/odpi/openmetadata/commonservices/generichandlers/OpenMetadataAPIMapper.java @@ -2657,4 +2657,7 @@ public class OpenMetadataAPIMapper public static final String INCOMPLETE_CLASSIFICATION_TYPE_GUID = "078432fb-a889-4a51-8ebe-9797becea9f1"; public static final String INCOMPLETE_CLASSIFICATION_TYPE_NAME = "Incomplete"; + + public static final String PROCESSING_STATE_CLASSIFICATION_TYPE_GUID = "261fb0aa-b884-4ee8-87ea-a60510e9751d"; + public static final String PROCESSING_STATE_CLASSIFICATION_TYPE_NAME = "ProcessingState"; } diff --git a/open-metadata-resources/open-metadata-archives/open-metadata-types/src/main/java/org/odpi/openmetadata/opentypes/OpenMetadataTypesArchive.java b/open-metadata-resources/open-metadata-archives/open-metadata-types/src/main/java/org/odpi/openmetadata/opentypes/OpenMetadataTypesArchive.java index 77effe3030f..58bbd4036d4 100644 --- a/open-metadata-resources/open-metadata-archives/open-metadata-types/src/main/java/org/odpi/openmetadata/opentypes/OpenMetadataTypesArchive.java +++ b/open-metadata-resources/open-metadata-archives/open-metadata-types/src/main/java/org/odpi/openmetadata/opentypes/OpenMetadataTypesArchive.java @@ -7,12 +7,16 @@ import org.odpi.openmetadata.repositoryservices.archiveutilities.OMRSArchiveHelper; import org.odpi.openmetadata.repositoryservices.connectors.stores.archivestore.properties.OpenMetadataArchive; import org.odpi.openmetadata.repositoryservices.connectors.stores.archivestore.properties.OpenMetadataArchiveType; +import org.odpi.openmetadata.repositoryservices.connectors.stores.metadatacollectionstore.properties.typedefs.ClassificationDef; import org.odpi.openmetadata.repositoryservices.connectors.stores.metadatacollectionstore.properties.typedefs.EntityDef; +import org.odpi.openmetadata.repositoryservices.connectors.stores.metadatacollectionstore.properties.typedefs.TypeDefAttribute; import org.odpi.openmetadata.repositoryservices.connectors.stores.metadatacollectionstore.properties.typedefs.TypeDefPatch; import org.odpi.openmetadata.repositoryservices.ffdc.OMRSErrorCode; import org.odpi.openmetadata.repositoryservices.ffdc.exception.OMRSLogicErrorException; +import java.util.ArrayList; import java.util.Date; +import java.util.List; /** * OpenMetadataTypesArchive builds an open metadata archive containing all the standard open metadata types. @@ -155,6 +159,7 @@ public void getOriginalTypes() * Calls for new and changed types go here */ add0053XRootSchemaType(); + add0042ProcessingStateClassification(); } @@ -164,6 +169,51 @@ public void getOriginalTypes() * ------------------------------------------------------------------------------------------------------- */ + /** + * 0042 Add the Processing State Classification + */ + private void add0042ProcessingStateClassification() + { + this.archiveBuilder.addClassificationDef(addProcessingStateClassification()); + } + + private ClassificationDef addProcessingStateClassification() { + final String guid = "261fb0aa-b884-4ee8-87ea-a60510e9751d"; + final String name = "ProcessingState"; + final String description = "Stores processing state information used by various SoftwareCapabilities."; + final String descriptionGUID = null; + + final String linkedToEntity = "SoftwareCapability"; + + ClassificationDef classificationDef = archiveHelper.getClassificationDef(guid, + name, + null, + description, + descriptionGUID, + this.archiveBuilder.getEntityDef(linkedToEntity), + true); + + /* + * Build the attributes + */ + List properties = new ArrayList<>(); + TypeDefAttribute property; + + final String attribute1Name = "syncDatesByKey"; + final String attribute1Description = "Collection of synchronization dates identified by a key"; + final String attribute1DescriptionGUID = null; + + property = archiveHelper.getMapStringLongTypeDefAttribute(attribute1Name, + attribute1Description, + attribute1DescriptionGUID); + + properties.add(property); + + classificationDef.setPropertiesDefinition(properties); + + return classificationDef; + } + private void add0053XRootSchemaType() {