All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.odpi.openmetadata.commonservices.generichandlers.ExternalIdentifierHandler Maven / Gradle / Ivy

The newest version!
/* SPDX-License-Identifier: Apache-2.0 */
/* Copyright Contributors to the ODPi Egeria project. */
package org.odpi.openmetadata.commonservices.generichandlers;

import org.odpi.openmetadata.frameworks.openmetadata.types.OpenMetadataProperty;
import org.odpi.openmetadata.frameworks.openmetadata.types.OpenMetadataType;
import org.odpi.openmetadata.commonservices.ffdc.InvalidParameterHandler;
import org.odpi.openmetadata.commonservices.generichandlers.ffdc.GenericHandlersAuditCode;
import org.odpi.openmetadata.commonservices.generichandlers.ffdc.GenericHandlersErrorCode;
import org.odpi.openmetadata.commonservices.repositoryhandler.RepositoryHandler;
import org.odpi.openmetadata.commonservices.repositoryhandler.RepositoryIteratorForEntities;
import org.odpi.openmetadata.commonservices.repositoryhandler.RepositoryRelatedEntitiesIterator;
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.metadatasecurity.server.OpenMetadataServerSecurityVerifier;
import org.odpi.openmetadata.frameworks.auditlog.AuditLog;
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.Relationship;
import org.odpi.openmetadata.repositoryservices.connectors.stores.metadatacollectionstore.repositoryconnector.OMRSRepositoryHelper;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * ExternalIdentifierHandler manages ExternalIdentifier objects.  These entities represent the identifiers used for metadata
 * in third party technology. It runs server-side in the OMAG Server Platform and manages ExternalId entities through the OMRSRepositoryConnector
 * via the repository handler.
 * The ExternalIdentifier is linked to the SoftwareCapability that represents the third party technology
 * that generated the external identifier.  This is referred to as the scope. It is also linked to the element
 * (or elements) in open metadata that are equivalent to the metadata element(s) in the third party technology.
 * The correlation may be many-to-many.
 *
 * @param  bean that returns an external identifier
 * @param  bean that returns the elements tied to this external identifier
 */
public class ExternalIdentifierHandler extends ReferenceableHandler
{
    private final OpenMetadataAPIGenericConverter elementConverter;
    private final Class                           elementBeanClass;


    /**
     * Construct the handler information needed to interact with the repository services
     *
     * @param converter specific converter for the EXTERNAL_ID bean class
     * @param beanClass name of bean class that is represented by the generic class EXTERNAL_ID
     * @param elementConverter specific converter for the OPEN_METADATA_ELEMENT_HEADER bean class
     * @param elementBeanClass name of bean class that is represented by the generic class OPEN_METADATA_ELEMENT_HEADER
     * @param serviceName name of this service
     * @param serverName name of the local server
     * @param invalidParameterHandler handler for managing parameter errors
     * @param repositoryHandler manages calls to the repository services
     * @param repositoryHelper provides utilities for manipulating the repository services objects
     * @param localServerUserId userId for this server
     * @param securityVerifier open metadata security services verifier
     * @param supportedZones list of zones that the access service is allowed to serve Asset instances from.
     * @param defaultZones list of zones that the access service should set in all new Asset instances.
     * @param publishZones list of zones that the access service sets up in published Asset instances.
     * @param auditLog destination for audit log events.
     */
    public ExternalIdentifierHandler(OpenMetadataAPIGenericConverter                  converter,
                                     Class                                            beanClass,
                                     OpenMetadataAPIGenericConverter elementConverter,
                                     Class                           elementBeanClass,
                                     String                                                        serviceName,
                                     String                                                        serverName,
                                     InvalidParameterHandler                                       invalidParameterHandler,
                                     RepositoryHandler                                             repositoryHandler,
                                     OMRSRepositoryHelper                                          repositoryHelper,
                                     String                                                        localServerUserId,
                                     OpenMetadataServerSecurityVerifier                            securityVerifier,
                                     List                                                  supportedZones,
                                     List                                                  defaultZones,
                                     List                                                  publishZones,
                                     AuditLog                                                      auditLog)
    {
        super(converter,
              beanClass,
              serviceName,
              serverName,
              invalidParameterHandler,
              repositoryHandler,
              repositoryHelper,
              localServerUserId,
              securityVerifier,
              supportedZones,
              defaultZones,
              publishZones,
              auditLog);

        this.elementConverter = elementConverter;
        this.elementBeanClass = elementBeanClass;
    }


    /**
     * Set up the ExternalIdentifier for the supplied element.  This external identifier may already exist for the requested
     * scope if multiple open metadata entities are needed to represent the metadata element(s) in the third party metadata source
     * that is identified by this ExternalIdentifier.
     *
     * @param userId calling userId
     * @param elementGUID unique identifier of the open metadata element to link to the external identifier
     * @param elementGUIDParameterName parameter supplying elementGUID
     * @param elementTypeName type of the element
     * @param identifier identifier from the third party technology (scope)
     * @param identifierParameterName name of parameter supplying identifier
     * @param identifierKeyPattern type of key pattern used in the third party technology (typically local key)
     * @param identifierDescription name of the identifier in the third party technology
     * @param identifierUsage usage information from the connector/client supplying the identifier
     * @param identifierSource name of the connector/client supplying the identifier
     * @param identifierMappingProperties additional properties to help with the synchronization
     * @param externalInstanceCreatedBy the username of the person or process that created the instance in the external system
     * @param externalInstanceCreationTime the date/time when the instance in the external system was created
     * @param externalInstanceLastUpdatedBy the username of the person or process that last updated the instance in the external system
     * @param externalInstanceLastUpdateTime the date/time that the instance in the external system was last updated
     * @param externalInstanceVersion the latest version of the element in the external system
     * @param scopeGUID unique identifier of the software capability that represents the third metadata source
     * @param scopeGUIDParameterName parameter supplying scopeGUID
     * @param scopeQualifiedName qualified name from the entity that
     * @param scopeTypeName specific type name of the software capability that represents the third party metadata source
     * @param scopeDomainName specific domain name of the software capability that represents the third party metadata source
     * @param permittedSynchronization direction of synchronization
     * @param synchronizationDescription optional description of the synchronization in progress (augments the description in the
     *                                   permitted synchronization enum)
     * @param serviceSupportedZones supported zones for calling service
     * @param effectiveFrom the date when this element is active - null for active now
     * @param effectiveTo the date when this element becomes inactive - null for active until deleted
     * @param forLineage return elements marked with the Memento classification?
     * @param forDuplicateProcessing do not merge elements marked as duplicates?
     * @param effectiveTime the time that the retrieved elements must be effective for (null for any time, new Date() for now)
     * @param methodName calling method
     *
     * @throws InvalidParameterException  one of the parameters is invalid
     * @throws UserNotAuthorizedException the user is not authorized to issue this request
     * @throws PropertyServerException    there is a problem reported in the open metadata server(s)
     */
    public void setUpExternalIdentifier(String              userId,
                                        String              elementGUID,
                                        String              elementGUIDParameterName,
                                        String              elementTypeName,
                                        String              identifier,
                                        String              identifierParameterName,
                                        int                 identifierKeyPattern,
                                        String              identifierDescription,
                                        String              identifierUsage,
                                        String              identifierSource,
                                        Map identifierMappingProperties,
                                        String              externalInstanceCreatedBy,
                                        Date                externalInstanceCreationTime,
                                        String              externalInstanceLastUpdatedBy,
                                        Date                externalInstanceLastUpdateTime,
                                        long                externalInstanceVersion,
                                        String              scopeGUID,
                                        String              scopeGUIDParameterName,
                                        String              scopeQualifiedName,
                                        String              scopeTypeName,
                                        String              scopeDomainName,
                                        int                 permittedSynchronization,
                                        String              synchronizationDescription,
                                        List        serviceSupportedZones,
                                        Date                effectiveFrom,
                                        Date                effectiveTo,
                                        boolean             forLineage,
                                        boolean             forDuplicateProcessing,
                                        Date                effectiveTime,
                                        String              methodName) throws InvalidParameterException,
                                                                               UserNotAuthorizedException,
                                                                               PropertyServerException
    {
        final String externalIdGUIDParameterName = "externalIdGUID";

        EntityDetail externalIdEntity = this.getExternalIdEntity(userId,
                                                                 identifier,
                                                                 identifierParameterName,
                                                                 scopeGUID,
                                                                 scopeGUIDParameterName,
                                                                 scopeQualifiedName,
                                                                 scopeTypeName,
                                                                 serviceSupportedZones,
                                                                 forLineage,
                                                                 forDuplicateProcessing,
                                                                 effectiveTime,
                                                                 methodName);

        String externalIdGUID;

        if (externalIdEntity == null)
        {
            /*
             * There is no external identifier and so it needs to be created and connected to the
             * scope and the element.
             */
            externalIdGUID = createExternalIdentifier(userId,
                                                      identifier,
                                                      identifierKeyPattern,
                                                      externalInstanceCreatedBy,
                                                      externalInstanceCreationTime,
                                                      externalInstanceLastUpdatedBy,
                                                      externalInstanceLastUpdateTime,
                                                      externalInstanceVersion,
                                                      scopeGUID,
                                                      scopeGUIDParameterName,
                                                      scopeTypeName,
                                                      scopeDomainName,
                                                      permittedSynchronization,
                                                      synchronizationDescription,
                                                      serviceSupportedZones,
                                                      effectiveFrom,
                                                      effectiveTo,
                                                      forLineage,
                                                      forDuplicateProcessing,
                                                      effectiveTime,
                                                      methodName);


            auditLog.logMessage(methodName,
                                GenericHandlersAuditCode.SETTING_UP_EXTERNAL_ID.getMessageDefinition(serviceName,
                                                                                                     elementTypeName,
                                                                                                     elementGUID,
                                                                                                     identifier,
                                                                                                     scopeQualifiedName,
                                                                                                     scopeGUID,
                                                                                                     methodName));
        }
        else
        {
            externalIdGUID = externalIdEntity.getGUID();

            updateExternalIdentifier(userId,
                                     externalIdGUID,
                                     externalIdGUIDParameterName,
                                     identifier,
                                     identifierKeyPattern,
                                     externalInstanceCreatedBy,
                                     externalInstanceCreationTime,
                                     externalInstanceLastUpdatedBy,
                                     externalInstanceLastUpdateTime,
                                     externalInstanceVersion,
                                     serviceSupportedZones,
                                     forLineage,
                                     forDuplicateProcessing,
                                     effectiveTime,
                                     methodName);
        }

        /*
         * Now check if the relationship currently exists between the element and the external id entity.
         */
        Relationship resourceLink = this.getResourceLinkRelationship(userId,
                                                                     elementGUID,
                                                                     elementGUIDParameterName,
                                                                     elementTypeName,
                                                                     externalIdGUID,
                                                                     serviceSupportedZones,
                                                                     forLineage,
                                                                     forDuplicateProcessing,
                                                                     effectiveTime,
                                                                     methodName);

        if (resourceLink == null)
        {
            /*
             * At this point the link between the element and the external id entity is missing and needs to be created
             */
            createExternalIdLink(userId,
                                 elementGUID,
                                 elementGUIDParameterName,
                                 elementTypeName,
                                 externalIdGUID,
                                 externalIdGUIDParameterName,
                                 identifierDescription,
                                 identifierUsage,
                                 identifierSource,
                                 identifierMappingProperties,
                                 serviceSupportedZones,
                                 effectiveFrom,
                                 effectiveTo,
                                 forLineage,
                                 forDuplicateProcessing,
                                 effectiveTime,
                                 methodName);
        }
        else
        {
            updateExternalIdLink(userId,
                                 resourceLink,
                                 identifierDescription,
                                 identifierUsage,
                                 identifierSource,
                                 identifierMappingProperties,
                                 methodName);
        }
    }


    /**
     * Create an audit log record to document that an external metadata source has created a relationship.
     *
     * @param scopeGUID unique identifier of the element representing the scope
     * @param scopeQualifiedName unique name of the element representing the scope
     * @param relationshipType type of relationship
     * @param end1GUID unique identifier for the entity at end 1 of the relationship
     * @param end1TypeName type of the entity at end 1 of the relationship
     * @param end2GUID unique identifier for the entity at end 2 of the relationship
     * @param end2TypeName type of the entity at end 2 of the relationship
     * @param methodName calling method
     */
    public  void logRelationshipCreation(String scopeGUID,
                                         String scopeQualifiedName,
                                         String relationshipType,
                                         String end1GUID,
                                         String end1TypeName,
                                         String end2GUID,
                                         String end2TypeName,
                                         String methodName)
    {
        if (scopeGUID != null)
        {
            auditLog.logMessage(methodName,
                                GenericHandlersAuditCode.NEW_EXTERNAL_RELATIONSHIP.getMessageDefinition(serviceName,
                                                                                                        relationshipType,
                                                                                                        end1TypeName,
                                                                                                        end1GUID,
                                                                                                        end2TypeName,
                                                                                                        end2GUID,
                                                                                                        methodName,
                                                                                                        scopeGUID,
                                                                                                        scopeQualifiedName));
        }
    }


    /**
     * Create an audit log record to document that an external metadata source has created a relationship.
     *
     * @param scopeGUID unique identifier of the element representing the scope
     * @param scopeQualifiedName unique name of the element representing the scope
     * @param relationshipType type of relationship
     * @param relationshipGUID unique identifier for the relationship
     * @param methodName calling method
     */
    public  void logRelationshipUpdate(String scopeGUID,
                                       String scopeQualifiedName,
                                       String relationshipType,
                                       String relationshipGUID,
                                       String methodName)
    {
        if (scopeGUID != null)
        {
            auditLog.logMessage(methodName,
                                GenericHandlersAuditCode.EXTERNAL_RELATIONSHIP_UPDATED.getMessageDefinition(serviceName,
                                                                                                            relationshipType,
                                                                                                            relationshipGUID,
                                                                                                            methodName,
                                                                                                            scopeGUID,
                                                                                                            scopeQualifiedName));
        }
    }


    /**
     * Create an audit log record to document that an external metadata source has removed a relationship.
     *
     * @param scopeGUID unique identifier of the element representing the scope
     * @param scopeQualifiedName unique name of the element representing the scope
     * @param relationshipType type of relationship
     * @param end1GUID unique identifier for the entity at end 1 of the relationship
     * @param end1TypeName type of the entity at end 1 of the relationship
     * @param end2GUID unique identifier for the entity at end 2 of the relationship
     * @param end2TypeName type of the entity at end 2 of the relationship
     * @param methodName calling method
     */
    public  void logRelationshipRemoval(String scopeGUID,
                                        String scopeQualifiedName,
                                        String relationshipType,
                                        String end1GUID,
                                        String end1TypeName,
                                        String end2GUID,
                                        String end2TypeName,
                                        String methodName)
    {
        if (scopeGUID != null)
        {
            auditLog.logMessage(methodName,
                                GenericHandlersAuditCode.EXTERNAL_RELATIONSHIP_REMOVED.getMessageDefinition(serviceName,
                                                                                                            relationshipType,
                                                                                                            end1TypeName,
                                                                                                            end1GUID,
                                                                                                            end2TypeName,
                                                                                                            end2GUID,
                                                                                                            methodName,
                                                                                                            scopeGUID,
                                                                                                            scopeQualifiedName));
        }
    }


    /**
     * Remove the ExternalIdentifier for the supplied element. The open metadata element is not affected.
     *
     * @param userId calling userId
     * @param elementGUID unique identifier of the open metadata element to link to the external identifier
     * @param elementGUIDParameterName parameter supplying elementGUID
     * @param elementTypeName type of the element
     * @param identifier identifier from the third party technology (scope)
     * @param identifierParameterName name of parameter supplying identifier
     * @param identifierKeyPattern type of key pattern used in the third party technology (typically local key)
     * @param identifierDescription name of the identifier in the third party technology
     * @param identifierUsage usage information from the connector/client supplying the identifier
     * @param identifierSource name of the connector/client supplying the identifier
     * @param identifierMappingProperties additional properties to help with the synchronization
     * @param scopeGUID unique identifier of the software capability that represents the third metadata source
     * @param scopeGUIDParameterName parameter supplying scopeGUID
     * @param scopeQualifiedName qualified name from the entity that
     * @param scopeTypeName specific type name of the software capability that represents the third party metadata source
     * @param permittedSynchronization direction of synchronization
     * @param synchronizationDescription optional description of the synchronization in progress (augments the description in the
     *                                   permitted synchronization enum)
     * @param serviceSupportedZones supported zones for calling service
     * @param forLineage return elements marked with the Memento classification?
     * @param forDuplicateProcessing do not merge elements marked as duplicates?
     * @param effectiveTime when should the elements be effected for - null is anytime; new Date() is now
     * @param methodName calling method
     * @throws InvalidParameterException  one of the parameters is invalid
     * @throws UserNotAuthorizedException the user is not authorized to issue this request
     * @throws PropertyServerException    there is a problem reported in the open metadata server(s)
     */
    public void removeExternalIdentifier(String              userId,
                                         String              elementGUID,
                                         String              elementGUIDParameterName,
                                         String              elementTypeName,
                                         String              identifier,
                                         String              identifierParameterName,
                                         int                 identifierKeyPattern,
                                         String              identifierDescription,
                                         String              identifierUsage,
                                         String              identifierSource,
                                         Map identifierMappingProperties,
                                         List        serviceSupportedZones,
                                         String              scopeGUID,
                                         String              scopeGUIDParameterName,
                                         String              scopeQualifiedName,
                                         String              scopeTypeName,
                                         int                 permittedSynchronization,
                                         String              synchronizationDescription,
                                         boolean             forLineage,
                                         boolean             forDuplicateProcessing,
                                         Date                effectiveTime,
                                         String              methodName) throws InvalidParameterException,
                                                                                UserNotAuthorizedException,
                                                                                PropertyServerException
    {
        // todo
    }


    /**
     * Confirm that the values of a particular metadata element have been synchronized.  This is important
     * from an audit points of view, and to allow bidirectional updates of metadata using optimistic locking.
     *
     * @param userId calling user
     * @param elementGUID unique identifier (GUID) of this element in open metadata
     * @param elementGUIDParameterName parameter supplying elementGUID
     * @param elementTypeName type of element being mapped
     * @param identifier unique identifier of this element in the external asset manager
     * @param identifierParameterName parameter supplying identifier
     * @param scopeGUID unique identifier of software capability representing the caller
     * @param scopeGUIDParameterName parameter name supplying scopeGUID
     * @param scopeQualifiedName unique name of the scope
     * @param scopeTypeName specific type name of the software capability that represents the third party metadata source
     * @param serviceSupportedZones supported zones for calling service
     * @param forLineage return elements marked with the Memento classification?
     * @param forDuplicateProcessing do not merge elements marked as duplicates?
     * @param effectiveTime the time that the retrieved elements must be effective for (null for any time, new Date() for now)
     * @param methodName calling method
     *
     * @return the identifier's entity
     *
     * @throws InvalidParameterException  one of the parameters is invalid
     * @throws UserNotAuthorizedException user not authorized to issue this request
     * @throws PropertyServerException    problem accessing the property server
     */
    public EntityDetail confirmSynchronization(String       userId,
                                               String       elementGUID,
                                               String       elementGUIDParameterName,
                                               String       elementTypeName,
                                               String       identifier,
                                               String       identifierParameterName,
                                               String       scopeGUID,
                                               String       scopeGUIDParameterName,
                                               String       scopeQualifiedName,
                                               String       scopeTypeName,
                                               List serviceSupportedZones,
                                               boolean      forLineage,
                                               boolean      forDuplicateProcessing,
                                               Date         effectiveTime,
                                               String       methodName) throws InvalidParameterException,
                                                                               UserNotAuthorizedException,
                                                                               PropertyServerException
    {
        invalidParameterHandler.validateGUID(elementGUID, elementGUIDParameterName, methodName);
        invalidParameterHandler.validateGUID(scopeGUID, scopeGUIDParameterName, methodName);
        invalidParameterHandler.validateName(identifier, identifierParameterName, methodName);

        EntityDetail externalIdEntity = this.getExternalIdEntity(userId,
                                                                 identifier,
                                                                 identifierParameterName,
                                                                 scopeGUID,
                                                                 scopeGUIDParameterName,
                                                                 scopeQualifiedName,
                                                                 scopeTypeName,
                                                                 serviceSupportedZones,
                                                                 forLineage,
                                                                 forDuplicateProcessing,
                                                                 effectiveTime,
                                                                 methodName);


        if (externalIdEntity == null)
        {
            throw new InvalidParameterException(GenericHandlersErrorCode.UNKNOWN_EXTERNAL_IDENTITY.getMessageDefinition(serviceName,
                                                                                                                        identifier,
                                                                                                                        scopeQualifiedName,
                                                                                                                        scopeGUID,
                                                                                                                        elementTypeName,
                                                                                                                        elementGUID),
                                                this.getClass().getName(),
                                                methodName,
                                                identifierParameterName);
        }

        /*
         * Now check if the relationship currently exists between the element and the external id entity.
         */
        Relationship resourceLink = this.getResourceLinkRelationship(userId,
                                                                     elementGUID,
                                                                     elementGUIDParameterName,
                                                                     elementTypeName,
                                                                     externalIdEntity.getGUID(),
                                                                     serviceSupportedZones,
                                                                     forLineage,
                                                                     forDuplicateProcessing,
                                                                     effectiveTime,
                                                                     methodName);

        if (resourceLink == null)
        {
            throw new InvalidParameterException(GenericHandlersErrorCode.UNKNOWN_RESOURCE_LINK.getMessageDefinition(serviceName,
                                                                                                                    identifier,
                                                                                                                    scopeQualifiedName,
                                                                                                                    scopeGUID,
                                                                                                                    elementTypeName,
                                                                                                                    elementGUID),
                                                this.getClass().getName(),
                                                methodName,
                                                identifierParameterName);
        }
        else
        {
            InstanceProperties newProperties;

            if (resourceLink.getProperties() == null)
            {
                newProperties = repositoryHelper.addDatePropertyToInstance(serviceName,
                                                                           null,
                                                                           OpenMetadataProperty.LAST_SYNCHRONIZED.name,
                                                                           new Date(),
                                                                           methodName);
            }
            else
            {
                newProperties = repositoryHelper.addDatePropertyToInstance(serviceName,
                                                                           new InstanceProperties(resourceLink.getProperties()),
                                                                           OpenMetadataProperty.LAST_SYNCHRONIZED.name,
                                                                           new Date(),
                                                                           methodName);
            }

            repositoryHandler.updateRelationshipProperties(userId,
                                                           null,
                                                           null,
                                                           resourceLink,
                                                           newProperties,
                                                           methodName);
        }

        return externalIdEntity;
    }


    /**
     * Retrieve the ExternalIdentifier for the supplied element.  This external identifier needs to cone form the correct scope.
     *
     * @param userId calling userId
     * @param identifier identifier from the third party technology (scope)
     * @param identifierParameterName name of parameter supplying the identifier
     * @param scopeGUID unique identifier of the software capability that represents the third metadata source
     * @param scopeGUIDParameterName parameter supplying scopeGUID
     * @param scopeQualifiedName unique name of the software capability that represents the third metadata source
     * @param scopeTypeName specific type name of the software capability that represents the third party metadata source
     * @param serviceSupportedZones supported zones for calling service
     * @param effectiveTime when should the elements be effected for - null is anytime; new Date() is now
     * @param forLineage return elements marked with the Memento classification?
     * @param forDuplicateProcessing do not merge elements marked as duplicates?
     * @param methodName calling method
     *
     * @return ExternalId entity for the supplied identifier and scope
     *
     * @throws InvalidParameterException  one of the parameters is invalid
     * @throws UserNotAuthorizedException user not authorized to issue this request
     * @throws PropertyServerException    problem accessing the property server
     */
    private EntityDetail getExternalIdEntity(String       userId,
                                             String       identifier,
                                             String       identifierParameterName,
                                             String       scopeGUID,
                                             String       scopeGUIDParameterName,
                                             String       scopeQualifiedName,
                                             String       scopeTypeName,
                                             List serviceSupportedZones,
                                             boolean      forLineage,
                                             boolean      forDuplicateProcessing,
                                             Date         effectiveTime,
                                             String       methodName) throws InvalidParameterException,
                                                                             UserNotAuthorizedException,
                                                                             PropertyServerException
    {
        invalidParameterHandler.validateGUID(scopeGUID, scopeGUIDParameterName, methodName);
        invalidParameterHandler.validateName(identifier, identifierParameterName, methodName);

        /*
         * Since the external identifier is not necessarily unique and is linked many-to-many, begin with
         * retrieving all the ExternalId entities with the same identifier.
         */
        List propertyNames = new ArrayList<>();

        propertyNames.add(OpenMetadataProperty.IDENTIFIER.name);

        int queryPageSize = invalidParameterHandler.getMaxPagingSize();

        RepositoryIteratorForEntities identifierIterator = getEntitySearchIterator(userId,
                                                                                   identifier,
                                                                                   OpenMetadataType.EXTERNAL_ID.typeGUID,
                                                                                   OpenMetadataType.EXTERNAL_ID.typeName,
                                                                                   propertyNames,
                                                                                   true,
                                                                                   false,
                                                                                   null,
                                                                                   null,
                                                                                   null,
                                                                                   forLineage,
                                                                                   forDuplicateProcessing,
                                                                                   0,
                                                                                   queryPageSize,
                                                                                   effectiveTime,
                                                                                   methodName);


        while (identifierIterator.moreToReceive())
        {
            /*
             * For each of the matching external identifiers validate the scope
             */
            EntityDetail externalIdEntity = identifierIterator.getNext();

            if (this.validateExternalIdentifierScope(userId,
                                                     identifier,
                                                     externalIdEntity,
                                                     scopeGUID,
                                                     scopeQualifiedName,
                                                     scopeTypeName,
                                                     serviceSupportedZones,
                                                     forLineage,
                                                     forDuplicateProcessing,
                                                     effectiveTime,
                                                     methodName))
            {
                return externalIdEntity;
            }
        }

        return null;
    }


    /**
     * Retrieve the ExternalIdLink relationship between the open metadata element and the external identifier.
     *
     * @param userId calling user
     * @param elementGUID unique identifier of the open metadata element to link to the external identifier
     * @param elementGUIDParameterName parameter supplying elementGUID
     * @param elementTypeName type of the element
     * @param externalIdGUID unique identifier of the ExternalId entity
     * @param serviceSupportedZones supported zones for calling service
     * @param forLineage return elements marked with the Memento classification?
     * @param forDuplicateProcessing do not merge elements marked as duplicates?
     * @param effectiveTime the time that the retrieved elements must be effective for (null for any time, new Date() for now)
     * @param methodName calling method
     *
     * @return ExternalIdLink relationship between the requested elements - or null
     *
     * @throws InvalidParameterException  one of the parameters is invalid
     * @throws UserNotAuthorizedException user not authorized to issue this request
     * @throws PropertyServerException    problem accessing the property server
     */
    private Relationship getResourceLinkRelationship(String  userId,
                                                     String  elementGUID,
                                                     String  elementGUIDParameterName,
                                                     String  elementTypeName,
                                                     String  externalIdGUID,
                                                     List serviceSupportedZones,
                                                     boolean forLineage,
                                                     boolean forDuplicateProcessing,
                                                     Date    effectiveTime,
                                                     String  methodName) throws InvalidParameterException,
                                                                                UserNotAuthorizedException,
                                                                                PropertyServerException
    {
        invalidParameterHandler.validateGUID(elementGUID, elementGUIDParameterName, methodName);

        /*
         * Now check if the relationship currently exists between the element and the external id entity.
         */
        List resourceLinks = this.getAttachmentLinks(userId,
                                                                   elementGUID,
                                                                   elementGUIDParameterName,
                                                                   elementTypeName,
                                                                   OpenMetadataType.EXTERNAL_ID_LINK_RELATIONSHIP.typeGUID,
                                                                   OpenMetadataType.EXTERNAL_ID_LINK_RELATIONSHIP.typeName,
                                                                   externalIdGUID,
                                                                   OpenMetadataType.EXTERNAL_ID.typeName,
                                                                   0,
                                                                   forLineage,
                                                                   forDuplicateProcessing,
                                                                   serviceSupportedZones,
                                                                   0,
                                                                   invalidParameterHandler.getMaxPagingSize(),
                                                                   effectiveTime,
                                                                   methodName);

        if (resourceLinks != null)
        {
            for (Relationship relationship : resourceLinks)
            {
                if ((relationship != null) && (relationship.getEntityOneProxy() != null))
                {
                    if (elementGUID.equals(relationship.getEntityOneProxy().getGUID()))
                    {
                        return relationship;
                    }
                }
            }
        }

        return null;
    }


    /**
     * Determine if the scope of an external identifier matches the requester's scope.  This test is needed
     * because it is possible that different third party technologies are using the same external identifier
     * for completely different elements.  This is why the external identifiers are always tied to a scope
     * to show where it is valid.
     *
     * @param userId calling userId
     * @param identifier identifier from the third party technology (scope)
     * @param externalIdEntity entity for the external identifier
     * @param scopeGUID unique identifier of the software capability that represents the third metadata source
     * @param scopeQualifiedName unique name of the software capability that represents the third metadata source
     * @param scopeTypeName specific type name of the software capability that represents the third party metadata source
     * @param serviceSupportedZones supported zones for calling service
     * @param forLineage return elements marked with the Memento classification?
     * @param forDuplicateProcessing do not merge elements marked as duplicates?
     * @param effectiveTime the time that the retrieved elements must be effective for (null for any time, new Date() for now)
     * @param methodName calling method
     *
     * @throws InvalidParameterException  one of the parameters is invalid
     * @throws UserNotAuthorizedException user not authorized to issue this request
     * @throws PropertyServerException    problem accessing the property server
     */
    private boolean validateExternalIdentifierScope(String       userId,
                                                    String       identifier,
                                                    EntityDetail externalIdEntity,
                                                    String       scopeGUID,
                                                    String       scopeQualifiedName,
                                                    String       scopeTypeName,
                                                    List serviceSupportedZones,
                                                    boolean      forLineage,
                                                    boolean      forDuplicateProcessing,
                                                    Date         effectiveTime,
                                                    String       methodName) throws InvalidParameterException,
                                                                                    UserNotAuthorizedException,
                                                                                    PropertyServerException
    {
        final String externalIdGUIDParameterName = "externalIdEntity.getGUID()";

        if ((externalIdEntity != null) && (externalIdEntity.getType() != null))
        {
            /*
             * An entity with the same identifier already exists - retrieve its relationships
             * to determine if connected to the same scope. An ordinary retrieve, rather than using an iterator,
             * is used because this number is expected to be small (number of external systems exchanging
             * metadata in the open metadata ecosystem that happens to use the same external identifier).
             */
            List externalIdScopes = this.getAttachmentLinks(userId,
                                                                          externalIdEntity.getGUID(),
                                                                          externalIdGUIDParameterName,
                                                                          OpenMetadataType.EXTERNAL_ID.typeName,
                                                                          OpenMetadataType.EXTERNAL_ID_SCOPE_RELATIONSHIP.typeGUID,
                                                                          OpenMetadataType.EXTERNAL_ID_SCOPE_RELATIONSHIP.typeName,
                                                                          scopeGUID,
                                                                          scopeTypeName,
                                                                          0,
                                                                          forLineage,
                                                                          forDuplicateProcessing,
                                                                          serviceSupportedZones,
                                                                          0,
                                                                          invalidParameterHandler.getMaxPagingSize(),
                                                                          effectiveTime,
                                                                          methodName);

            return externalIdScopes != null;
        }
        else
        {
            /*
             * Throw logic error exception
             */
            throw new PropertyServerException(GenericHandlersErrorCode.NULL_EXTERNAL_ID_ENTITY.getMessageDefinition(identifier,
                                                                                                                    scopeTypeName,
                                                                                                                    scopeQualifiedName,
                                                                                                                    scopeGUID),
                                              this.getClass().getName(),
                                              methodName);
        }
    }


    /**
     * Create a new external Identifier and attach it to its valid scope.
     *
     * @param userId calling user
     * @param identifier identifier from the third party technology
     * @param identifierKeyPattern key pattern that defines the logic used to maintain the identifier
     * @param externalInstanceCreatedBy the username of the person or process that created the instance in the external system
     * @param externalInstanceCreationTime the date/time when the instance in the external system was created
     * @param externalInstanceLastUpdatedBy the username of the person or process that last updated the instance in the external system
     * @param externalInstanceLastUpdateTime the date/time that the instance in the external system was last updated
     * @param externalInstanceVersion the latest version of the element in the external system
     * @param scopeGUID unique identifier of the software capability that represents the third metadata source
     * @param scopeGUIDParameterName parameter supplying scopeGUID
     * @param scopeTypeName specific type name of the software capability that represents the third party metadata source
     * @param scopeDomainName specific type name of the software capability that represents the third party metadata source
     * @param permittedSynchronization direction of synchronization
     * @param synchronizationDescription optional description of the synchronization in progress (augments the description in the
     *                                   permitted synchronization enum)
     * @param serviceSupportedZones supported zones for calling service
     * @param effectiveFrom the date when this element is active - null for active now
     * @param effectiveTo the date when this element becomes inactive - null for active until deleted
     * @param forLineage return elements marked with the Memento classification?
     * @param forDuplicateProcessing do not merge elements marked as duplicates?
     * @param effectiveTime what is the effective time for related queries needed to do the update
     * @param methodName calling method
     *
     * @return unique identifier of the new external id entity
     *
     * @throws InvalidParameterException  one of the parameters is invalid
     * @throws UserNotAuthorizedException user not authorized to issue this request
     * @throws PropertyServerException    problem accessing the property server
     */
    private String createExternalIdentifier(String       userId,
                                            String       identifier,
                                            int          identifierKeyPattern,
                                            String       externalInstanceCreatedBy,
                                            Date         externalInstanceCreationTime,
                                            String       externalInstanceLastUpdatedBy,
                                            Date         externalInstanceLastUpdateTime,
                                            long         externalInstanceVersion,
                                            String       scopeGUID,
                                            String       scopeGUIDParameterName,
                                            String       scopeTypeName,
                                            String       scopeDomainName,
                                            int          permittedSynchronization,
                                            String       synchronizationDescription,
                                            List serviceSupportedZones,
                                            Date         effectiveFrom,
                                            Date         effectiveTo,
                                            boolean      forLineage,
                                            boolean      forDuplicateProcessing,
                                            Date         effectiveTime,
                                            String       methodName) throws InvalidParameterException,
                                                                            UserNotAuthorizedException,
                                                                            PropertyServerException
    {
        final String externalIdGUIDParameterName = "externalIdentifierGUID";


        ExternalIdentifierBuilder builder = new ExternalIdentifierBuilder(identifier,
                                                                          identifierKeyPattern,
                                                                          externalInstanceCreatedBy,
                                                                          externalInstanceCreationTime,
                                                                          externalInstanceLastUpdatedBy,
                                                                          externalInstanceLastUpdateTime,
                                                                          externalInstanceVersion,
                                                                          repositoryHelper,
                                                                          serviceName,
                                                                          serverName);

        builder.setAnchors(userId,
                           scopeGUID,
                           scopeTypeName,
                           scopeDomainName,
                           methodName);

        builder.setEffectivityDates(effectiveFrom, effectiveTo);

        String externalIdGUID = this.createBeanInRepository(userId,
                                                            null,
                                                            null,
                                                            OpenMetadataType.EXTERNAL_ID.typeGUID,
                                                            OpenMetadataType.EXTERNAL_ID.typeName,
                                                            builder,
                                                            effectiveTime,
                                                            methodName);

        if (externalIdGUID != null)
        {
            InstanceProperties scopeProperties = builder.getExternalIdScopeProperties(synchronizationDescription,
                                                                                      permittedSynchronization,
                                                                                      methodName);
            this.uncheckedLinkElementToElement(userId,
                                               null,
                                               null,
                                               scopeGUID,
                                               scopeGUIDParameterName,
                                               scopeTypeName,
                                               externalIdGUID,
                                               externalIdGUIDParameterName,
                                               OpenMetadataType.EXTERNAL_ID.typeName,
                                               forLineage,
                                               forDuplicateProcessing,
                                               serviceSupportedZones,
                                               OpenMetadataType.EXTERNAL_ID_SCOPE_RELATIONSHIP.typeGUID,
                                               OpenMetadataType.EXTERNAL_ID_SCOPE_RELATIONSHIP.typeName,
                                               scopeProperties,
                                               effectiveTime,
                                               methodName);

        }

        return externalIdGUID;
    }


    /**
     * Create a new external Identifier and attach it to its valid scope.
     *
     * @param userId calling user
     * @param externalIdGUID unique identifier of the
     * @param identifier identifier from the third party technology
     * @param identifierKeyPattern key pattern that defines the logic used to maintain the identifier
     * @param externalInstanceCreatedBy the username of the person or process that created the instance in the external system
     * @param externalInstanceCreationTime the date/time when the instance in the external system was created
     * @param externalInstanceLastUpdatedBy the username of the person or process that last updated the instance in the external system
     * @param externalInstanceLastUpdateTime the date/time that the instance in the external system was last updated
     * @param externalInstanceVersion the latest version of the element in the external system
     * @param serviceSupportedZones supported zones for calling service
     * @param effectiveTime when should the elements be effected for - null is anytime; new Date() is now
     * @param forLineage return elements marked with the Memento classification?
     * @param forDuplicateProcessing do not merge elements marked as duplicates?
     * @param methodName calling method
     *
     * @throws InvalidParameterException  one of the parameters is invalid
     * @throws UserNotAuthorizedException user not authorized to issue this request
     * @throws PropertyServerException    problem accessing the property server
     */
    private void updateExternalIdentifier(String       userId,
                                          String       externalIdGUID,
                                          String       externalIdGUIDParameterName,
                                          String       identifier,
                                          int          identifierKeyPattern,
                                          String       externalInstanceCreatedBy,
                                          Date         externalInstanceCreationTime,
                                          String       externalInstanceLastUpdatedBy,
                                          Date         externalInstanceLastUpdateTime,
                                          long         externalInstanceVersion,
                                          List serviceSupportedZones,
                                          boolean      forLineage,
                                          boolean      forDuplicateProcessing,
                                          Date         effectiveTime,
                                          String       methodName) throws InvalidParameterException,
                                                                          UserNotAuthorizedException,
                                                                          PropertyServerException
    {
        ExternalIdentifierBuilder builder = new ExternalIdentifierBuilder(identifier,
                                                                          identifierKeyPattern,
                                                                          externalInstanceCreatedBy,
                                                                          externalInstanceCreationTime,
                                                                          externalInstanceLastUpdatedBy,
                                                                          externalInstanceLastUpdateTime,
                                                                          externalInstanceVersion,
                                                                          repositoryHelper,
                                                                          serviceName,
                                                                          serverName);

        this.updateBeanInRepository(userId,
                                    null,
                                    null,
                                    externalIdGUID,
                                    externalIdGUIDParameterName,
                                    OpenMetadataType.EXTERNAL_ID.typeGUID,
                                    OpenMetadataType.EXTERNAL_ID.typeName,
                                    forLineage,
                                    forDuplicateProcessing,
                                    serviceSupportedZones,
                                    builder.getInstanceProperties(methodName),
                                    true,
                                    effectiveTime,
                                    methodName);
    }


    /**
     * Create the relationship between an open metadata element and an external id.
     *
     * @param userId calling user
     * @param elementGUID unique identifier of the open metadata element to link to the external identifier
     * @param elementGUIDParameterName parameter supplying elementGUID
     * @param elementTypeName type of the element
     * @param identifierDescription name of the identifier in the third party technology
     * @param identifierUsage usage information from the connector/client supplying the identifier
     * @param identifierSource name of the connector/client supplying the identifier
     * @param externalIdGUID unique identifier of the external id entity
     * @param externalIdGUIDParameterName parameter supplying externalIdGUID
     * @param identifierMappingProperties additional properties used to manage the mapping to the elements in the third party technology
     * @param serviceSupportedZones supported zones for calling service
     * @param effectiveFrom the date when this element is active - null for active now
     * @param effectiveTo the date when this element becomes inactive - null for active until deleted
     * @param forLineage return elements marked with the Memento classification?
     * @param forDuplicateProcessing do not merge elements marked as duplicates?
     * @param effectiveTime what is the effective time for related queries needed to do the update
     * @param methodName calling method
     *
     * @throws InvalidParameterException  one of the parameters is invalid
     * @throws UserNotAuthorizedException user not authorized to issue this request
     * @throws PropertyServerException    problem accessing the property server
     */
    private void createExternalIdLink(String              userId,
                                      String              elementGUID,
                                      String              elementGUIDParameterName,
                                      String              elementTypeName,
                                      String              externalIdGUID,
                                      String              externalIdGUIDParameterName,
                                      String              identifierDescription,
                                      String              identifierUsage,
                                      String              identifierSource,
                                      Map identifierMappingProperties,
                                      List        serviceSupportedZones,
                                      Date                effectiveFrom,
                                      Date                effectiveTo,
                                      boolean             forLineage,
                                      boolean             forDuplicateProcessing,
                                      Date                effectiveTime,
                                      String              methodName) throws InvalidParameterException,
                                                                             UserNotAuthorizedException,
                                                                             PropertyServerException
    {
        ExternalIdentifierBuilder builder = new ExternalIdentifierBuilder(repositoryHelper, serviceName, serverName);

        InstanceProperties resourceLinkProperties = builder.getExternalIdResourceLinkProperties(identifierDescription,
                                                                                                identifierUsage,
                                                                                                identifierSource,
                                                                                                identifierMappingProperties,
                                                                                                methodName);

        builder.setEffectivityDates(effectiveFrom, effectiveTo);

        this.linkElementToElement(userId,
                                  null,
                                  null,
                                  elementGUID,
                                  elementGUIDParameterName,
                                  elementTypeName,
                                  externalIdGUID,
                                  externalIdGUIDParameterName,
                                  OpenMetadataType.EXTERNAL_ID.typeName,
                                  forLineage,
                                  forDuplicateProcessing,
                                  serviceSupportedZones,
                                  OpenMetadataType.EXTERNAL_ID_LINK_RELATIONSHIP.typeGUID,
                                  OpenMetadataType.EXTERNAL_ID_LINK_RELATIONSHIP.typeName,
                                  resourceLinkProperties,
                                  effectiveFrom,
                                  effectiveTo,
                                  effectiveTime,
                                  methodName);
    }


    /**
     * Create the relationship between an open metadata element and an external id.
     *
     * @param userId calling user
     * @param externalIdLink existing relationship
     * @param identifierDescription name of the identifier in the third party technology
     * @param identifierUsage usage information from the connector/client supplying the identifier
     * @param identifierSource name of the connector/client supplying the identifier
     * @param identifierMappingProperties additional properties used to manage the mapping to the elements in the third party technology
     * @param methodName calling method
     *
     * @throws UserNotAuthorizedException user not authorized to issue this request
     * @throws PropertyServerException    problem accessing the property server
     */
    private void updateExternalIdLink(String              userId,
                                      Relationship        externalIdLink,
                                      String              identifierDescription,
                                      String              identifierUsage,
                                      String              identifierSource,
                                      Map identifierMappingProperties,
                                      String              methodName) throws UserNotAuthorizedException,
                                                                             PropertyServerException
    {
        ExternalIdentifierBuilder builder = new ExternalIdentifierBuilder(repositoryHelper, serviceName, serverName);

        if (externalIdLink != null)
        {
            /*
             * Only update the relationship if things have changed (this rarely happens).
             */
            InstanceProperties existingProperties = externalIdLink.getProperties();

            if ((propertyUpdateNeeded(identifierDescription, OpenMetadataProperty.DESCRIPTION.name, existingProperties, methodName)) ||
                (propertyUpdateNeeded(identifierUsage, OpenMetadataProperty.USAGE.name, existingProperties, methodName)) ||
                (propertyUpdateNeeded(identifierSource, OpenMetadataProperty.SOURCE.name, existingProperties, methodName)))
            {
                InstanceProperties properties = builder.getExternalIdResourceLinkProperties(identifierDescription,
                                                                                            identifierUsage,
                                                                                            identifierSource,
                                                                                            identifierMappingProperties,
                                                                                            methodName);

                repositoryHandler.updateRelationshipProperties(userId,
                                                               null,
                                                               null,
                                                               externalIdLink,
                                                               properties,
                                                               methodName);
            }
        }
    }


    /**
     * Test if a string property needs updating.
     *
     * @param newValue new value
     * @param propertyName name of the property
     * @param existingProperties properties currently stored
     * @param methodName calling method
     *
     * @return boolean flag - true if the property needs updating
     */
    private boolean propertyUpdateNeeded(String             newValue,
                                         String             propertyName,
                                         InstanceProperties existingProperties,
                                         String             methodName)
    {
        String existingValue = repositoryHelper.getStringProperty(serviceName,
                                                                  propertyName,
                                                                  existingProperties,
                                                                  methodName);

        if ((existingValue == null) && (newValue == null))
        {
            return false;
        }

        if (existingValue == null)
        {
            return true;
        }

        return  (! existingValue.equals(newValue));
    }


    /**
     * Update and validate the properties associated with the ExternalIdScope relationship.
     *
     * @param userId calling userId
     * @param externalIdScope scope relationship
     * @param permittedSynchronization direction of synchronization
     * @param synchronizationDescription optional description of the synchronization in progress (augments the description in the permitted synchronization enum)
     * @param methodName calling method
     *
     * @throws InvalidParameterException  one of the parameters is invalid
     * @throws UserNotAuthorizedException user not authorized to issue this request
     * @throws PropertyServerException    problem accessing the property server
     */
    private void updateScopeProperties(String       userId,
                                       Relationship externalIdScope,
                                       int          permittedSynchronization,
                                       String       synchronizationDescription,
                                       String       methodName) throws InvalidParameterException,
                                                                       UserNotAuthorizedException,
                                                                       PropertyServerException
    {
        ExternalIdentifierBuilder builder = new ExternalIdentifierBuilder(repositoryHelper, serviceName, serverName);

        /*
         * The properties for this synchronization are not set up - make the changes
         */
        InstanceProperties properties = builder.getExternalIdScopeProperties(synchronizationDescription,
                                                                             permittedSynchronization,
                                                                             methodName);

        repositoryHandler.updateRelationshipProperties(userId,
                                                       null,
                                                       null,
                                                       externalIdScope,
                                                       properties,
                                                       methodName);
    }


    /**
     * Return the external identifiers attached to a referenceable by the ExternalIdLink.
     *
     * @param userId     calling user
     * @param elementGUID identifier for the entity that the identifier is attached to
     * @param elementGUIDParameterName name of parameter supplying the GUID
     * @param elementTypeName name of the type of object being attached to
     * @param serviceSupportedZones supported zones for calling service
     * @param startingFrom where to start from in the list
     * @param pageSize maximum number of results that can be returned
     * @param forLineage return elements marked with the Memento classification?
     * @param forDuplicateProcessing do not merge elements marked as duplicates?
     * @param effectiveTime the time that the retrieved elements must be effective for
     * @param methodName calling method
     *
     * @return list of retrieved objects or null if none found
     *
     * @throws InvalidParameterException  the input properties are invalid
     * @throws UserNotAuthorizedException user not authorized to issue this request
     * @throws PropertyServerException    problem accessing the property server
     */
    public List getExternalIdentifiersForElement(String       userId,
                                                              String       elementGUID,
                                                              String       elementGUIDParameterName,
                                                              String       elementTypeName,
                                                              List serviceSupportedZones,
                                                              int          startingFrom,
                                                              int          pageSize,
                                                              boolean      forLineage,
                                                              boolean      forDuplicateProcessing,
                                                              Date         effectiveTime,
                                                              String       methodName) throws InvalidParameterException,
                                                                                              PropertyServerException,
                                                                                              UserNotAuthorizedException
    {
        return this.getExternalIdentifiersForScope(userId,
                                                   elementGUID,
                                                   elementGUIDParameterName,
                                                   elementTypeName,
                                                   serviceSupportedZones,
                                                   null,
                                                   OpenMetadataType.REFERENCEABLE.typeName,
                                                   null,
                                                   startingFrom,
                                                   pageSize,
                                                   forLineage,
                                                   forDuplicateProcessing,
                                                   effectiveTime,
                                                   methodName);
    }


    /**
     * Return the external identifiers attached to a referenceable by the ExternalIdLink.
     *
     * @param userId     calling user
     * @param elementGUID identifier for the entity that the identifier is attached to
     * @param elementGUIDParameterName name of parameter supplying the GUID
     * @param elementTypeName name of the type of object being attached to
     * @param scopeGUID unique identifier of the software capability that represents the third metadata source
     * @param scopeTypeName specific type name of the software capability that represents the third party metadata source
     * @param scopeQualifiedName unique name of the software capability that represents the third metadata source
     * @param startingFrom where to start from in the list
     * @param pageSize maximum number of results that can be returned
     * @param forLineage return elements marked with the Memento classification?
     * @param forDuplicateProcessing do not merge elements marked as duplicates?
     * @param effectiveTime the time that the retrieved elements must be effective for
     * @param methodName calling method
     *
     * @return list of retrieved objects or null if none found
     *
     * @throws InvalidParameterException  the input properties are invalid
     * @throws UserNotAuthorizedException user not authorized to issue this request
     * @throws PropertyServerException    problem accessing the property server
     */
    public List getExternalIdentifiersForScope(String  userId,
                                                            String  elementGUID,
                                                            String  elementGUIDParameterName,
                                                            String  elementTypeName,
                                                            String  scopeGUID,
                                                            String  scopeTypeName,
                                                            String  scopeQualifiedName,
                                                            boolean forLineage,
                                                            boolean forDuplicateProcessing,
                                                            int     startingFrom,
                                                            int     pageSize,
                                                            Date    effectiveTime,
                                                            String  methodName) throws InvalidParameterException,
                                                                                       PropertyServerException,
                                                                                       UserNotAuthorizedException
    {
        return getExternalIdentifiersForScope(userId,
                                              elementGUID,
                                              elementGUIDParameterName,
                                              elementTypeName,
                                              supportedZones,
                                              scopeGUID,
                                              scopeTypeName,
                                              scopeQualifiedName,
                                              startingFrom,
                                              pageSize,
                                              forLineage,
                                              forDuplicateProcessing,
                                              effectiveTime,
                                              methodName);
    }


    /**
     * Return the external identifiers attached to a referenceable by the ExternalIdLink.
     *
     * @param userId     calling user
     * @param elementGUID identifier for the entity that the identifier is attached to
     * @param elementGUIDParameterName name of parameter supplying the GUID
     * @param elementTypeName name of the type of object being attached to
     * @param serviceSupportedZones supported zones for calling service
     * @param scopeGUID unique identifier of the software capability that represents the third metadata source
     * @param scopeTypeName specific type name of the software capability that represents the third party metadata source
     * @param scopeQualifiedName unique name of the software capability that represents the third party metadata source
     * @param startingFrom where to start from in the list
     * @param pageSize maximum number of results that can be returned
     * @param forLineage return elements marked with the Memento classification?
     * @param forDuplicateProcessing do not merge elements marked as duplicates?
     * @param effectiveTime the time that the retrieved elements must be effective for
     * @param methodName calling method
     *
     * @return list of retrieved objects or null if none found
     *
     * @throws InvalidParameterException  the input properties are invalid
     * @throws UserNotAuthorizedException user not authorized to issue this request
     * @throws PropertyServerException    problem accessing the property server
     */
    public List getExternalIdentifiersForScope(String       userId,
                                                            String       elementGUID,
                                                            String       elementGUIDParameterName,
                                                            String       elementTypeName,
                                                            List serviceSupportedZones,
                                                            String       scopeGUID,
                                                            String       scopeTypeName,
                                                            String       scopeQualifiedName,
                                                            int          startingFrom,
                                                            int          pageSize,
                                                            boolean      forLineage,
                                                            boolean      forDuplicateProcessing,
                                                            Date         effectiveTime,
                                                            String       methodName) throws InvalidParameterException,
                                                                                            PropertyServerException,
                                                                                            UserNotAuthorizedException
    {
        invalidParameterHandler.validateGUID(elementGUID, elementGUIDParameterName, methodName);

        List results = new ArrayList<>();

        List externalIdLinks = this.getAttachmentLinks(userId,
                                                                     elementGUID,
                                                                     elementGUIDParameterName,
                                                                     elementTypeName,
                                                                     OpenMetadataType.EXTERNAL_ID_LINK_RELATIONSHIP.typeGUID,
                                                                     OpenMetadataType.EXTERNAL_ID_LINK_RELATIONSHIP.typeName,
                                                                     null,
                                                                     OpenMetadataType.EXTERNAL_ID.typeName,
                                                                     0,
                                                                     forLineage,
                                                                     forDuplicateProcessing,
                                                                     serviceSupportedZones,
                                                                     startingFrom,
                                                                     pageSize,
                                                                     effectiveTime,
                                                                     methodName);

        if (externalIdLinks != null)
        {
            for (Relationship externalIdLink : externalIdLinks)
            {
                if ((externalIdLink != null) && (externalIdLink.getEntityTwoProxy()!= null))
                {
                    final String externalIdGUIDParameterName = "externalIdLink.getEntityTwoProxy().getGUID()";

                    String externalIdGUID = externalIdLink.getEntityTwoProxy().getGUID();

                    EntityDetail externalIdEntity = this.getEntityFromRepository(userId,
                                                                                 externalIdGUID,
                                                                                 externalIdGUIDParameterName,
                                                                                 OpenMetadataType.EXTERNAL_ID.typeName,
                                                                                 null,
                                                                                 null,
                                                                                 forLineage,
                                                                                 forDuplicateProcessing,
                                                                                 serviceSupportedZones,
                                                                                 effectiveTime,
                                                                                 methodName);

                    if ((externalIdEntity != null) && (externalIdEntity.getType() != null))
                    {
                        List externalIdScopes = this.getAttachmentLinks(userId,
                                                                                      externalIdEntity,
                                                                                      externalIdGUIDParameterName,
                                                                                      OpenMetadataType.EXTERNAL_ID.typeName,
                                                                                      OpenMetadataType.EXTERNAL_ID_SCOPE_RELATIONSHIP.typeGUID,
                                                                                      OpenMetadataType.EXTERNAL_ID_SCOPE_RELATIONSHIP.typeName,
                                                                                      null,
                                                                                      scopeTypeName,
                                                                                      0,
                                                                                      forLineage,
                                                                                      forDuplicateProcessing,
                                                                                      serviceSupportedZones,
                                                                                      startingFrom,
                                                                                      pageSize,
                                                                                      effectiveTime,
                                                                                      methodName);

                        if (externalIdScopes != null)
                        {
                            for (Relationship externalIdScope : externalIdScopes)
                            {
                                if ((externalIdScope != null) && (externalIdScope.getEntityOneProxy() != null))
                                {
                                    if ((scopeGUID == null) ||
                                        (scopeGUID.equals(externalIdScope.getEntityOneProxy().getGUID())))
                                    {
                                        List externalIdRelationships = new ArrayList<>();

                                        externalIdRelationships.add(externalIdLink);
                                        externalIdRelationships.add(externalIdScope);

                                        EXTERNAL_ID bean = converter.getNewComplexBean(beanClass,
                                                                                       externalIdEntity,
                                                                                       externalIdRelationships,
                                                                                       methodName);

                                        if (bean != null)
                                        {
                                            results.add(bean);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        if (results.isEmpty())
        {
            return null;
        }

        return results;
    }


    /**
     * Return the list of entities for open metadata elements of an open metadata type that are associated with an
     * external identifier in a particular scope.
     *
     * @param userId calling user
     * @param scopeGUID unique identifier of software capability representing the caller
     * @param scopeParameterName unique name of software capability representing the caller
     * @param scopeTypeName specific type name of the software capability that represents the third party metadata source
     * @param requestedTypeName unique type name of the elements in the external asset manager
     * @param startingFrom where to start from in the list
     * @param pageSize maximum number of results that can be returned
     * @param forLineage return elements marked with the Memento classification?
     * @param forDuplicateProcessing do not merge elements marked as duplicates?
     * @param effectiveTime  the time that the retrieved elements must be effective for (null for any time, new Date() for now)
     * @param methodName calling method
     *
     * @return list of element headers
     *
     * @throws InvalidParameterException  one of the parameters is invalid
     * @throws UserNotAuthorizedException user not authorized to issue this request
     * @throws PropertyServerException    problem accessing the property server
     */
    public List getElementEntitiesForScope(String  userId,
                                                         String  scopeGUID,
                                                         String  scopeParameterName,
                                                         String  scopeTypeName,
                                                         String  requestedTypeName,
                                                         int     startingFrom,
                                                         int     pageSize,
                                                         Date    effectiveTime,
                                                         boolean      forLineage,
                                                         boolean      forDuplicateProcessing,
                                                         String       methodName) throws InvalidParameterException,
                                                                                         UserNotAuthorizedException,
                                                                                         PropertyServerException
    {
        final String requestedTypeNameParameterName = "requestedTypeName";

        invalidParameterHandler.validateGUID(scopeGUID, scopeParameterName, methodName);
        invalidParameterHandler.validateName(requestedTypeName, requestedTypeNameParameterName, methodName);
        int queryPageSize = invalidParameterHandler.validatePaging(startingFrom, pageSize, methodName);

        RepositoryRelatedEntitiesIterator externalIdIterator = new RepositoryRelatedEntitiesIterator(repositoryHandler,
                                                                                                     invalidParameterHandler,
                                                                                                     userId,
                                                                                                     scopeGUID,
                                                                                                     scopeTypeName,
                                                                                                     OpenMetadataType.EXTERNAL_ID_SCOPE_RELATIONSHIP.typeGUID,
                                                                                                     OpenMetadataType.EXTERNAL_ID_SCOPE_RELATIONSHIP.typeName,
                                                                                                     null,
                                                                                                     forLineage,
                                                                                                     forDuplicateProcessing,
                                                                                                     0,
                                                                                                     0,
                                                                                                     effectiveTime,
                                                                                                     methodName);

        int skippedResults = 0;
        List results = new ArrayList<>();

        while ((externalIdIterator.moreToReceive()) && ((queryPageSize == 0) || results.size() < queryPageSize))
        {
            EntityDetail externalIdEntity = externalIdIterator.getNext();

            if (externalIdEntity != null)
            {
                RepositoryRelatedEntitiesIterator elementIterator = new RepositoryRelatedEntitiesIterator(repositoryHandler,
                                                                                                          invalidParameterHandler,
                                                                                                          userId,
                                                                                                          externalIdEntity.getGUID(),
                                                                                                          OpenMetadataType.EXTERNAL_ID.typeName,
                                                                                                          OpenMetadataType.EXTERNAL_ID_LINK_RELATIONSHIP.typeGUID,
                                                                                                          OpenMetadataType.EXTERNAL_ID_LINK_RELATIONSHIP.typeName,
                                                                                                          null,
                                                                                                          forLineage,
                                                                                                          forDuplicateProcessing,
                                                                                                          0,
                                                                                                          0,
                                                                                                          effectiveTime,
                                                                                                          methodName);

                while ((externalIdIterator.moreToReceive()) && ((queryPageSize == 0) || results.size() < queryPageSize))
                {
                    EntityDetail elementEntity = elementIterator.getNext();

                    if ((elementEntity != null) && (elementEntity.getType() != null))
                    {
                        if (repositoryHelper.isTypeOf(serviceName, elementEntity.getType().getTypeDefName(), requestedTypeName))
                        {
                            if (skippedResults < startingFrom)
                            {
                                skippedResults ++;
                            }
                            else
                            {
                                results.add(elementEntity);
                            }
                        }
                    }
                }
            }
        }

        if (results.isEmpty())
        {
            return null;
        }
        else
        {
            return results;
        }
    }


    /**
     * Return the list of headers for open metadata elements that are associated with a particular
     * external identifier.  It is necessary to navigate to the externalIdentifier from the scope.
     *
     * @param userId calling user
     * @param scopeGUID unique identifier of software capability representing the caller
     * @param scopeParameterName unique name of software capability representing the caller
     * @param scopeTypeName specific type name of the software capability that represents the third party metadata source
     * @param scopeQualifiedName unique name of the software capability that represents the third party metadata source
     * @param externalIdentifier unique identifier of this element in the external asset manager
     * @param serviceSupportedZones zones from the calling service
     * @param startingFrom where to start from in the list
     * @param pageSize maximum number of results that can be returned
     * @param effectiveTime when should the elements be effected for - null is anytime; new Date() is now
     * @param forLineage return elements marked with the Memento classification?
     * @param forDuplicateProcessing do not merge elements marked as duplicates?
     * @param methodName calling method
     *
     * @return list of element headers
     *
     * @throws InvalidParameterException  one of the parameters is invalid
     * @throws UserNotAuthorizedException user not authorized to issue this request
     * @throws PropertyServerException    problem accessing the property server
     */
    public List getElementsForExternalIdentifier(String       userId,
                                                                               String       scopeGUID,
                                                                               String       scopeParameterName,
                                                                               String       scopeTypeName,
                                                                               String       scopeQualifiedName,
                                                                               String       externalIdentifier,
                                                                               List serviceSupportedZones,
                                                                               int          startingFrom,
                                                                               int          pageSize,
                                                                               boolean      forLineage,
                                                                               boolean      forDuplicateProcessing,
                                                                               Date         effectiveTime,
                                                                               String       methodName) throws InvalidParameterException,
                                                                                                               UserNotAuthorizedException,
                                                                                                               PropertyServerException
    {
        final String externalIdentifierParameterName = "externalIdentifier";

        invalidParameterHandler.validateGUID(scopeGUID, scopeParameterName, methodName);
        invalidParameterHandler.validateName(externalIdentifier, externalIdentifierParameterName, methodName);

        List propertyNames = new ArrayList<>();

        propertyNames.add(OpenMetadataProperty.IDENTIFIER.name);

        List matchingExternalIds = this.getEntitiesByValue(userId,
                                                                         externalIdentifier,
                                                                         externalIdentifierParameterName,
                                                                         OpenMetadataType.EXTERNAL_ID.typeGUID,
                                                                         OpenMetadataType.EXTERNAL_ID.typeName,
                                                                         propertyNames,
                                                                         true,
                                                                         false,
                                                                         null,
                                                                         null,
                                                                         forLineage,
                                                                         forDuplicateProcessing,
                                                                         serviceSupportedZones,
                                                                         null,
                                                                         0,
                                                                         invalidParameterHandler.getMaxPagingSize(),
                                                                         effectiveTime,
                                                                         methodName);


        if (matchingExternalIds != null)
        {
            final String matchingEntityGUIDParameterName = "matchingEntity.getGUID()";

            for (EntityDetail matchingExternalId : matchingExternalIds)
            {
                if (matchingExternalId != null)
                {
                    /*
                     * Is this externalId connected to the right scope
                     */
                    List externalIdRelationships = this.getAttachmentLinks(userId,
                                                                                         matchingExternalId,
                                                                                         matchingEntityGUIDParameterName,
                                                                                         OpenMetadataType.EXTERNAL_ID.typeName,
                                                                                         OpenMetadataType.EXTERNAL_ID_SCOPE_RELATIONSHIP.typeGUID,
                                                                                         OpenMetadataType.EXTERNAL_ID_SCOPE_RELATIONSHIP.typeName,
                                                                                         scopeGUID,
                                                                                         scopeTypeName,
                                                                                         1,
                                                                                         forLineage,
                                                                                         forDuplicateProcessing,
                                                                                         serviceSupportedZones,
                                                                                         0,
                                                                                         invalidParameterHandler.getMaxPagingSize(),
                                                                                         effectiveTime,
                                                                                         methodName);

                    if ((externalIdRelationships != null) && (externalIdRelationships.isEmpty()))
                    {
                        /*
                         * ExternalId is connected to the right scope
                         */
                        return this.getElementHeaders(userId,
                                                      matchingExternalId,
                                                      matchingEntityGUIDParameterName,
                                                      serviceSupportedZones,
                                                      startingFrom,
                                                      pageSize,
                                                      forLineage,
                                                      forDuplicateProcessing,
                                                      effectiveTime,
                                                      methodName);
                    }
                }
            }
        }

        return null;
    }


    /**
     * Return the list of headers for open metadata elements that are associated with a particular
     * external identifier.  It is necessary to navigate to the externalIdentifier.
     *
     * @param userId calling user
     * @param externalId unique identifier of software capability representing the caller
     * @param externalIdGUIDParameterName unique name of software capability representing the caller
     * @param serviceSupportedZones supported zones for calling service
     * @param startingFrom where to start from in the list
     * @param pageSize maximum number of results that can be returned
     * @param forLineage return elements marked with the Memento classification?
     * @param forDuplicateProcessing do not merge elements marked as duplicates?
     * @param effectiveTime the time that the retrieved elements must be effective for
     * @param methodName calling method
     *
     * @return list of element headers
     *
     * @throws InvalidParameterException  one of the parameters is invalid
     * @throws UserNotAuthorizedException user not authorized to issue this request
     * @throws PropertyServerException    problem accessing the property server
     */
    private List getElementHeaders(String       userId,
                                                                 EntityDetail externalId,
                                                                 String       externalIdGUIDParameterName,
                                                                 List serviceSupportedZones,
                                                                 int          startingFrom,
                                                                 int          pageSize,
                                                                 boolean      forLineage,
                                                                 boolean      forDuplicateProcessing,
                                                                 Date         effectiveTime,
                                                                 String       methodName) throws InvalidParameterException,
                                                                                                 UserNotAuthorizedException,
                                                                                                 PropertyServerException
    {
        List elementEntities = this.getAttachedEntities(userId,
                                                                      externalId,
                                                                      externalIdGUIDParameterName,
                                                                      OpenMetadataType.EXTERNAL_ID.typeName,
                                                                      OpenMetadataType.EXTERNAL_ID_LINK_RELATIONSHIP.typeGUID,
                                                                      OpenMetadataType.EXTERNAL_ID_LINK_RELATIONSHIP.typeName,
                                                                      OpenMetadataType.OPEN_METADATA_ROOT.typeName,
                                                                      null,
                                                                      null,
                                                                      1,
                                                                      forLineage,
                                                                      forDuplicateProcessing,
                                                                      serviceSupportedZones,
                                                                      startingFrom,
                                                                      pageSize,
                                                                      effectiveTime,
                                                                      methodName);

        List results = new ArrayList<>();

        if (elementEntities != null)
        {
            for (EntityDetail elementEntity : elementEntities)
            {
                if (elementEntity != null)
                {
                    OPEN_METADATA_ELEMENT_HEADER bean = elementConverter.getNewBean(elementBeanClass,
                                                                                    elementEntity,
                                                                                    methodName);

                    if (bean != null)
                    {
                        results.add(bean);
                    }
                }
            }
        }

        if (results.isEmpty())
        {
            return null;
        }

        return results;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy