You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by da...@apache.org on 2018/02/16 09:52:26 UTC

[10/30] atlas git commit: ATLAS-2246: OMRS Connector API plus REST and IGC Connector skeleton - 15th February 2018

http://git-wip-us.apache.org/repos/asf/atlas/blob/8a57e657/omrs/src/main/java/org/apache/atlas/omrs/localrepository/repositorycontentmanager/OMRSRepositoryContentManager.java
----------------------------------------------------------------------
diff --git a/omrs/src/main/java/org/apache/atlas/omrs/localrepository/repositorycontentmanager/OMRSRepositoryContentManager.java b/omrs/src/main/java/org/apache/atlas/omrs/localrepository/repositorycontentmanager/OMRSRepositoryContentManager.java
new file mode 100644
index 0000000..c146be6
--- /dev/null
+++ b/omrs/src/main/java/org/apache/atlas/omrs/localrepository/repositorycontentmanager/OMRSRepositoryContentManager.java
@@ -0,0 +1,2056 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.atlas.omrs.localrepository.repositorycontentmanager;
+
+import org.apache.atlas.omrs.auditlog.OMRSAuditCode;
+import org.apache.atlas.omrs.auditlog.OMRSAuditLog;
+import org.apache.atlas.omrs.auditlog.OMRSAuditingComponent;
+import org.apache.atlas.omrs.eventmanagement.*;
+import org.apache.atlas.omrs.eventmanagement.events.OMRSTypeDefEventProcessor;
+import org.apache.atlas.omrs.ffdc.OMRSErrorCode;
+import org.apache.atlas.omrs.ffdc.exception.*;
+import org.apache.atlas.omrs.localrepository.repositoryconnector.LocalOMRSRepositoryConnector;
+import org.apache.atlas.omrs.metadatacollection.OMRSMetadataCollection;
+import org.apache.atlas.omrs.metadatacollection.properties.instances.EntityDetail;
+import org.apache.atlas.omrs.metadatacollection.properties.instances.InstanceStatus;
+import org.apache.atlas.omrs.metadatacollection.properties.instances.InstanceType;
+import org.apache.atlas.omrs.metadatacollection.properties.instances.Relationship;
+import org.apache.atlas.omrs.metadatacollection.properties.typedefs.*;
+import org.apache.atlas.omrs.metadatacollection.repositoryconnector.OMRSRepositoryConnector;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * OMRSRepositoryContentManager supports an in-memory cache of TypeDefs for the local server.  It is used by the OMRS
+ * components for constructing metadata instances with valid types.   It ensures that the TypeDefs used in other
+ * members of the open metadata repository cohorts that the local server is also a member of are consistent with the
+ * local repository.
+ *
+ * OMRSRepositoryContentManager plays a central role in ensuring the integrity of the metadata in the local repository.
+ * It is called from multiple components at different points in the processing.  It presents a different interface
+ * to each of these components that is specialized to their needs.
+ * <ul>
+ *     <li>
+ *         OMRSTypeDefEventProcessor - processes inbound events from remote members of the open metadata
+ *         repository cohorts that the local repository is connected to.  These incoming TypeDef events need to
+ *         be validated against the types used locally and either saved or discarded depending on the exchange rule
+ *         setting.
+ *     </li>
+ *     <li>
+ *         OMRSTypeDefManager - provides maintenance methods for managing the TypeDefs in the local cache.
+ *     </li>
+ *     <li>
+ *         OMRSTypeDefHelper - provides methods to help OMRS connectors and adapters manage TypeDefs.
+ *     </li>
+ *     <li>
+ *         OMRSTypeDefValidator - provides methods to validate TypeDefs.
+ *     </li>
+ *     <li>
+ *         OMRSInstanceValidator - provides methods to help validate instances.
+ *     </li>
+ * </ul>
+ */
+public class OMRSRepositoryContentManager implements OMRSTypeDefEventProcessor,
+                                                     OMRSTypeDefManager,
+                                                     OMRSTypeDefHelper,
+                                                     OMRSTypeDefValidator,
+                                                     OMRSInstanceValidator
+{
+    private String                            localMetadataCollectionId      = null;
+    private LocalOMRSRepositoryConnector      localRepositoryConnector       = null;
+    private OMRSRepositoryEventManager        outboundRepositoryEventManager = null;
+    private OMRSRepositoryConnector           realLocalConnector             = null;
+    private OMRSRepositoryEventExchangeRule   saveExchangeRule               = null;
+    private String                            openTypesOriginGUID            = null;
+    private HashMap<String, TypeDef>          knownTypes                     = new HashMap<>();
+    private HashMap<String, AttributeTypeDef> knownAttributeTypes            = new HashMap<>();
+    private HashMap<String, TypeDef>          activeTypes                    = null;
+    private HashMap<String, AttributeTypeDef> activeAttributeTypes           = null;
+
+
+
+    /*
+     * The audit log provides a verifiable record of the open metadata archives that have been loaded into
+     * the open metadata repository.  The Logger is for standard debug.
+     */
+    private static final OMRSAuditLog auditLog = new OMRSAuditLog(OMRSAuditingComponent.TYPEDEF_MANAGER);
+    private static final Logger       log      = LoggerFactory.getLogger(OMRSRepositoryContentManager.class);
+
+
+
+    /**
+     * Default constructor
+     */
+    public OMRSRepositoryContentManager()
+    {
+
+    }
+
+
+    /**
+     * Saves all of the information necessary to process incoming TypeDef events.
+     *
+     * @param localRepositoryConnector - connector to the local repository
+     * @param realLocalConnector - connector to the real local repository - used for processing TypeDef events
+     * @param saveExchangeRule - rule that determines which events to process.
+     * @param outboundRepositoryEventManager - event manager to call for outbound events - used to send out reports
+     *                                       of conflicting TypeDefs
+     */
+    public void setupEventProcessor(LocalOMRSRepositoryConnector      localRepositoryConnector,
+                                    OMRSRepositoryConnector           realLocalConnector,
+                                    OMRSRepositoryEventExchangeRule   saveExchangeRule,
+                                    OMRSRepositoryEventManager        outboundRepositoryEventManager)
+    {
+        this.localRepositoryConnector       = localRepositoryConnector;
+        this.realLocalConnector             = realLocalConnector;
+        this.saveExchangeRule               = saveExchangeRule;
+        this.localMetadataCollectionId      = localRepositoryConnector.getMetadataCollectionId();
+        this.outboundRepositoryEventManager = outboundRepositoryEventManager;
+    }
+
+
+    /**
+     * Save the unique identifier of the open metadata archive.  This is stored in the origin property of
+     * all of the open metadata types.  It is needed to support the isOpenType() method.
+     *
+     * @param openMetadataTypesGUID - unique identifier for the open metadata type's archive
+     */
+    public void setOpenMetadataTypesOriginGUID(String openMetadataTypesGUID)
+    {
+        openTypesOriginGUID = openMetadataTypesGUID;
+    }
+
+
+    /*
+     * ========================
+     * OMRSTypeDefManager
+     */
+
+    /**
+     * Cache a definition of a new TypeDef.  This method assumes the TypeDef has been successfully added to the
+     * local repository already and all that is needed is to maintain the cached list of types
+     *
+     * @param sourceName - source of the request (used for logging)
+     * @param newTypeDef - TypeDef structure describing the new TypeDef.
+     */
+    public void addTypeDef(String  sourceName, TypeDef      newTypeDef)
+    {
+        if (this.validTypeDef(sourceName, newTypeDef))
+        {
+            knownTypes.put(newTypeDef.getName(), newTypeDef);
+            if (localRepositoryConnector != null)
+            {
+                activeTypes.put(newTypeDef.getName(), newTypeDef);
+
+                if (log.isDebugEnabled())
+                {
+                    log.debug("New Active Type " + newTypeDef.getName() + " from " + sourceName, newTypeDef);
+                }
+
+                // TODO log new active type
+            }
+        }
+    }
+
+
+    /**
+     * Cache a definition of a new AttributeTypeDef.
+     *
+     * @param sourceName - source of the request (used for logging)
+     * @param newAttributeTypeDef - AttributeTypeDef structure describing the new TypeDef.
+     */
+    public void addAttributeTypeDef(String  sourceName, AttributeTypeDef newAttributeTypeDef)
+    {
+
+    }
+
+    /**
+     * Update one or more properties of a cached TypeDef.  This method assumes the TypeDef has been successfully
+     * updated in the local repository already and all that is needed is to maintain the cached list of types
+     *
+     * @param sourceName - source of the request (used for logging)
+     * @param typeDef - TypeDef structure.
+     */
+    public void updateTypeDef(String  sourceName, TypeDef   typeDef)
+    {
+        if (this.validTypeDef(sourceName, typeDef))
+        {
+            knownTypes.put(typeDef.getName(), typeDef);
+            if (localRepositoryConnector != null)
+            {
+                activeTypes.put(typeDef.getName(), typeDef);
+
+                if (log.isDebugEnabled())
+                {
+                    log.debug("Updated Active Type " + typeDef.getName() + " from " + sourceName, typeDef);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Delete a cached TypeDef.
+     *
+     * @param sourceName - source of the request (used for logging)
+     * @param obsoleteTypeDefGUID - String unique identifier for the TypeDef.
+     * @param obsoleteTypeDefName - String unique name for the TypeDef.
+     */
+    public void deleteTypeDef(String    sourceName,
+                              String    obsoleteTypeDefGUID,
+                              String    obsoleteTypeDefName)
+    {
+        if (this.validTypeId(sourceName, obsoleteTypeDefGUID, obsoleteTypeDefName))
+        {
+            knownTypes.remove(obsoleteTypeDefName);
+
+            if (localRepositoryConnector != null)
+            {
+                activeTypes.remove(obsoleteTypeDefName);
+
+                if (log.isDebugEnabled())
+                {
+                    log.debug("Deleted Active Type " + obsoleteTypeDefName + " from " + sourceName);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Delete a cached AttributeTypeDef.
+     *
+     * @param sourceName - source of the request (used for logging)
+     * @param obsoleteTypeDefGUID - String unique identifier for the AttributeTypeDef.
+     * @param obsoleteTypeDefName - String unique name for the AttributeTypeDef.
+     */
+    public void deleteAttributeTypeDef(String    sourceName,
+                                       String    obsoleteTypeDefGUID,
+                                       String    obsoleteTypeDefName)
+    {
+
+    }
+
+
+    /**
+     * Change the identifiers for a TypeDef.
+     *
+     * @param sourceName - source of the request (used for logging).
+     * @param originalTypeDefGUID - TypeDef's original unique identifier.
+     * @param originalTypeDefName - TypeDef's original unique name.
+     * @param newTypeDef - updated TypeDef with new identifiers.
+     */
+    public void reIdentifyTypeDef(String   sourceName,
+                                  String   originalTypeDefGUID,
+                                  String   originalTypeDefName,
+                                  TypeDef  newTypeDef)
+    {
+        // TODO
+    }
+
+
+    /**
+     * Change the identifiers for an AttributeTypeDef.
+     *
+     * @param sourceName - source of the request (used for logging).
+     * @param originalAttributeTypeDefGUID - AttributeTypeDef's original unique identifier.
+     * @param originalAttributeTypeDefName - AttributeTypeDef's original unique name.
+     * @param newAttributeTypeDef - updated AttributeTypeDef with new identifiers
+     */
+    public void reIdentifyAttributeTypeDef(String            sourceName,
+                                           String            originalAttributeTypeDefGUID,
+                                           String            originalAttributeTypeDefName,
+                                           AttributeTypeDef  newAttributeTypeDef)
+    {
+        // TODO
+    }
+
+
+    /**
+     * Return the list of property names defined for this TypeDef.
+     *
+     * @param sourceName - source of the request (used for logging)
+     * @param typeDef - type definition to work with.
+     * @return list of String property names
+     * @throws TypeErrorException - there is an issue with the TypeDef.
+     */
+    private ArrayList<String>  getPropertyNames(String sourceName, TypeDef   typeDef) throws TypeErrorException
+    {
+        final  String                  methodName = "getPropertyNames()";
+        ArrayList<String>              propertyNames = null;
+
+        if (validTypeDef(sourceName, typeDef))
+        {
+            ArrayList<TypeDefAttribute>    propertiesDefinition = typeDef.getPropertiesDefinition();
+
+            if ((propertiesDefinition != null) && (propertiesDefinition.size() > 0))
+            {
+                propertyNames = new ArrayList<>();
+
+                for (TypeDefAttribute  propertyDefinition : propertiesDefinition)
+                {
+                    if (propertyDefinition != null)
+                    {
+                        String propertyName = propertyDefinition.getAttributeName();
+
+                        if (propertyName != null)
+                        {
+                            if (log.isDebugEnabled())
+                            {
+                                log.debug(typeDef.getName()  + " from " + sourceName + " has property " + propertyName);
+                            }
+                            propertyNames.add(propertyName);
+                        }
+                        else
+                        {
+                            OMRSErrorCode errorCode = OMRSErrorCode.BAD_TYPEDEF_ATTRIBUTE_NAME;
+                            String errorMessage = errorCode.getErrorMessageId()
+                                                + errorCode.getFormattedErrorMessage(sourceName);
+
+                            throw new TypeErrorException(errorCode.getHTTPErrorCode(),
+                                                         this.getClass().getName(),
+                                                         methodName,
+                                                         errorMessage,
+                                                         errorCode.getSystemAction(),
+                                                         errorCode.getUserAction());
+                        }
+                    }
+                    else
+                    {
+                        OMRSErrorCode errorCode = OMRSErrorCode.NULL_TYPEDEF_ATTRIBUTE;
+                        String errorMessage = errorCode.getErrorMessageId()
+                                            + errorCode.getFormattedErrorMessage(sourceName);
+
+                        throw new TypeErrorException(errorCode.getHTTPErrorCode(),
+                                                     this.getClass().getName(),
+                                                     methodName,
+                                                     errorMessage,
+                                                     errorCode.getSystemAction(),
+                                                     errorCode.getUserAction());
+                    }
+                }
+
+                /*
+                 * If no property names have been extracted then remove the array.
+                 */
+                if (propertyNames.size() == 0)
+                {
+                    propertyNames = null;
+                }
+            }
+        }
+        else
+        {
+            OMRSErrorCode errorCode = OMRSErrorCode.BAD_TYPEDEF;
+            String errorMessage = errorCode.getErrorMessageId()
+                                + errorCode.getFormattedErrorMessage(sourceName);
+
+            throw new TypeErrorException(errorCode.getHTTPErrorCode(),
+                                         this.getClass().getName(),
+                                         methodName,
+                                         errorMessage,
+                                         errorCode.getSystemAction(),
+                                         errorCode.getUserAction());
+        }
+
+        return propertyNames;
+    }
+
+
+    /**
+     * Return identifiers for the TypeDef that matches the supplied type name.  If the type name is not recognized,
+     * null is returned.
+     *
+     * @param sourceName - source of the request (used for logging)
+     * @param category - category of the instance type required.
+     * @param typeName - String type name.
+     * @return InstanceType object containing TypeDef properties such as unique identifier (guid),
+     *                             typeDef name and version name
+     * @throws TypeErrorException - the type name is not a recognized type or is of the wrong category or there is
+     *                              a problem with the cached TypeDef.
+     */
+    public InstanceType getInstanceType(String           sourceName,
+                                        TypeDefCategory  category,
+                                        String           typeName) throws TypeErrorException
+    {
+        final  String                  methodName = "getInstanceType()";
+
+        if (isValidTypeCategory(sourceName, category, typeName))
+        {
+            TypeDef typeDef = knownTypes.get(typeName);
+
+            if (typeDef != null)
+            {
+                InstanceType    instanceType = new InstanceType();
+
+                instanceType.setTypeDefCategory(category);
+                instanceType.setTypeDefGUID(typeDef.getGUID());
+                instanceType.setTypeDefName(typeDef.getName());
+                instanceType.setTypeDefVersion(typeDef.getVersion());
+                instanceType.setTypeDefDescription(typeDef.getDescription());
+                instanceType.setTypeDefDescriptionGUID(typeDef.getDescriptionGUID());
+
+                /*
+                 * Extract the properties for this TypeDef.  These will be augmented with property names
+                 * from the super type(s).
+                 */
+                ArrayList<String>      propertyNames = this.getPropertyNames(sourceName, typeDef);
+
+                /*
+                 * If propertyNames is null, it means the TypeDef has no attributes.  However the superType
+                 * may have attributes and so we need an array to accumulate the attributes into.
+                 */
+                if (propertyNames == null)
+                {
+                    propertyNames = new ArrayList<>();
+                }
+
+                /*
+                 * Work up the TypeDef hierarchy extracting the property names and super type names.
+                 */
+                ArrayList<TypeDefLink> superTypes    = new ArrayList<>();
+                TypeDefLink            superTypeLink = typeDef.getSuperType();
+
+                while (superTypeLink != null)
+                {
+                    String                 superTypeName = superTypeLink.getName();
+
+                    if (superTypeName != null)
+                    {
+                        if (log.isDebugEnabled())
+                        {
+                            log.debug(typeName + " from " + sourceName + " has super type " + superTypeName);
+                        }
+
+                        superTypes.add(superTypeLink);
+
+                        TypeDef                superTypeDef  = knownTypes.get(superTypeName);
+
+                        if (superTypeDef != null)
+                        {
+                            ArrayList<String>      superTypePropertyNames = this.getPropertyNames(sourceName, superTypeDef);
+
+                            if (superTypePropertyNames != null)
+                            {
+                                propertyNames.addAll(0, superTypePropertyNames);
+                            }
+                        }
+
+                        superTypeLink = superTypeDef.getSuperType();
+                    }
+                    else
+                    {
+                        superTypeLink = null;
+                    }
+                }
+
+                /*
+                 * Make sure empty lists are converted to nulls
+                 */
+
+                if (superTypes.size() > 0)
+                {
+                    instanceType.setTypeDefSuperTypes(superTypes);
+                }
+
+                if (propertyNames.size() > 0)
+                {
+                    instanceType.setValidInstanceProperties(propertyNames);
+                }
+            }
+        }
+        else
+        {
+            OMRSErrorCode errorCode = OMRSErrorCode.BAD_CATEGORY_FOR_TYPEDEF_ATTRIBUTE;
+            String errorMessage = errorCode.getErrorMessageId()
+                                + errorCode.getFormattedErrorMessage(sourceName, typeName, category.getTypeName());
+
+            throw new TypeErrorException(errorCode.getHTTPErrorCode(),
+                                         this.getClass().getName(),
+                                         methodName,
+                                         errorMessage,
+                                         errorCode.getSystemAction(),
+                                         errorCode.getUserAction());
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Return a boolean indicating that the type name matches the category.
+     *
+     * @param sourceName - source of the request (used for logging)
+     * @param category - TypeDefCategory enum value to test
+     * @param typeName - type name to test
+     * @return - boolean flag indicating that the type name is of the specified category
+     * @throws TypeErrorException - the type name is not a recognized type or there is
+     *                              a problem with the cached TypeDef.
+     */
+    public boolean    isValidTypeCategory(String            sourceName,
+                                          TypeDefCategory   category,
+                                          String            typeName) throws TypeErrorException
+    {
+        if (category == null)
+        {
+            // TODO throw logic error
+        }
+
+        if (typeName == null)
+        {
+            // TODO throw logic error
+        }
+
+        TypeDef   typeDef = knownTypes.get(typeName);
+
+        if (typeDef != null)
+        {
+            TypeDefCategory  retrievedTypeDefCategory = typeDef.getCategory();
+
+            if (retrievedTypeDefCategory != null)
+            {
+                if (category.getTypeCode() == retrievedTypeDefCategory.getTypeCode())
+                {
+                    return true;
+                }
+                else
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                // TODO Throw logic error
+            }
+        }
+
+        return false;
+    }
+
+
+    /**
+     * Return boolean indicating if a classification type can be applied to a specified entity.  This
+     * uses the list of valid entity types located in the ClassificationDef.
+     *
+     * @param sourceName - source of the request (used for logging)
+     * @param classificationTypeName - name of the classification's type (ClassificationDef)
+     * @param entityTypeName - name of the entity's type (EntityDef)
+     * @return boolean indicating if the classification is valid for the entity.
+     */
+    public boolean    isValidClassificationForEntity(String  sourceName,
+                                                     String  classificationTypeName,
+                                                     String  entityTypeName)
+    {
+        try
+        {
+            if ((isValidTypeCategory(sourceName, TypeDefCategory.CLASSIFICATION_DEF, classificationTypeName)) &&
+                (isValidTypeCategory(sourceName, TypeDefCategory.ENTITY_DEF, entityTypeName)))
+            {
+                ClassificationDef  classificationTypeDef = (ClassificationDef)knownTypes.get(classificationTypeName);
+
+                if (classificationTypeDef != null)
+                {
+                    ArrayList<TypeDefLink>   entityDefs = classificationTypeDef.getValidEntityDefs();
+
+                    if (entityDefs == null)
+                    {
+                        /*
+                         * The classification has no restrictions on which entities it can be attached to.
+                         */
+                        return true;
+                    }
+                    else
+                    {
+                        /*
+                         * The classification can only be attached to the entities listed.  Note an empty list
+                         * means the classification can not be attached to any entity and it is effectively useless.
+                         */
+                        for (TypeDefLink  allowedEntity : entityDefs)
+                        {
+                            if (allowedEntity != null)
+                            {
+                                if (entityTypeName.equals(allowedEntity.getName()))
+                                {
+                                    return true;
+                                }
+                            }
+                        }
+
+                        return false;
+                    }
+                }
+                else
+                {
+                    // TODO log audit record - logic error
+                    return false;
+                }
+            }
+            else
+            {
+                return false;
+            }
+        }
+        catch (TypeErrorException   typeError)
+        {
+            // TODO log audit record - invalid Types
+            return false;
+        }
+        catch (ClassCastException   castError)
+        {
+            // TODO log audit record - logic error - category not matching TypeDef instance type
+            return false;
+        }
+    }
+
+
+    /**
+     * Return the list of valid InstanceStatus states that instances of this type can handle.
+     *
+     * @param sourceName - source of the request (used for logging)
+     * @param typeName - name of the type
+     * @return list of InstanceStatus enums
+     * @throws TypeErrorException - the type name is not recognized.
+     */
+    public ArrayList<InstanceStatus> getValidStatusList(String  sourceName, String typeName) throws TypeErrorException
+    {
+        if (typeName == null)
+        {
+            // TODO throw TypeError Exception
+        }
+
+        TypeDef   typeDef = knownTypes.get(typeName);
+
+        if (typeDef == null)
+        {
+            // TODO throw TypeError exception
+        }
+
+        return typeDef.getValidInstanceStatusList();
+    }
+
+
+    /**
+     * Return the initial status value to use for an instance of the supplied type.
+     *
+     * @param sourceName - source of the request (used for logging)
+     * @param typeName - name of the type to extract the initial status from.
+     * @return InstanceStatus enum
+     * @throws TypeErrorException - the type name is not recognized.
+     */
+    public InstanceStatus getInitialStatus(String  sourceName, String typeName) throws TypeErrorException
+    {
+        if (typeName == null)
+        {
+            // TODO throw TypeError Exception
+        }
+
+        TypeDef   typeDef = knownTypes.get(typeName);
+
+        if (typeDef == null)
+        {
+            // TODO throw TypeError exception
+        }
+
+        return typeDef.getInitialStatus();
+    }
+
+
+    /**
+     * Return the URL string to use for direct access to the metadata instance.  This can be used for
+     * entities and relationships.  However, not all servers support direct access, in which case, this
+     * URL is null.
+     *
+     * @param sourceName - source of the request (used for logging)
+     * @param guid - unique identifier for the instance.
+     * @return String URL with placeholder for variables such as userId.
+     */
+    public String getInstanceURL(String  sourceName, String guid)
+    {
+        // TODO Need to work out what instance URL's look like for OMRS instances.  These URLs will be supported
+        // TODO by the REST API
+        return null;
+    }
+
+
+    /*
+     * ========================
+     * OMRSTypeDefHelper
+     */
+
+    /**
+     * Return the TypeDef identified by the name supplied by the caller.  This is used in the connectors when
+     * validating the actual types of the repository with the known open metadata types - looking specifically
+     * for types of the same name but with different content.
+     *
+     * @param sourceName - source of the request (used for logging)
+     * @param typeDefName - unique name for the TypeDef
+     * @return TypeDef object or null if TypeDef is not known.
+     */
+    public TypeDef  getTypeDefByName (String    sourceName,
+                                      String    typeDefName)
+    {
+        return knownTypes.get(typeDefName);
+    }
+
+
+    /**
+     * Return the AttributeTypeDef identified by the name supplied by the caller.  This is used in the connectors when
+     * validating the actual types of the repository with the known open metadata types - looking specifically
+     * for types of the same name but with different content.
+     *
+     * @param sourceName - source of the request (used for logging)
+     * @param attributeTypeDefName - unique name for the TypeDef
+     * @return AttributeTypeDef object or null if AttributeTypeDef is not known.
+     */
+    public AttributeTypeDef getAttributeTypeDefByName (String    sourceName,
+                                                       String    attributeTypeDefName)
+    {
+        return knownAttributeTypes.get(attributeTypeDefName);
+    }
+
+
+    /**
+     * Return the TypeDef identified by the guid and name supplied by the caller.  This call is used when
+     * retrieving a type that should exist.  For example, retrieving the type of a metadata instance.
+     *
+     * @param sourceName - source of the request (used for logging)
+     * @param typeDefGUID - unique identifier for the TypeDef
+     * @param typeDefName - unique name for the TypeDef
+     * @return TypeDef object
+     * @throws TypeErrorException - unknown or invalid type
+     */
+    public TypeDef  getTypeDef (String    sourceName,
+                                String    typeDefGUID,
+                                String    typeDefName) throws TypeErrorException
+    {
+        if (validTypeId(sourceName, typeDefGUID, typeDefName))
+        {
+            return knownTypes.get(typeDefName);
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * Return the AttributeTypeDef identified by the guid and name supplied by the caller.  This call is used when
+     * retrieving a type that should exist.  For example, retrieving the type definition of a metadata instance's
+     * property.
+     *
+     * @param sourceName - source of the request (used for logging)
+     * @param attributeTypeDefGUID - unique identifier for the AttributeTypeDef
+     * @param attributeTypeDefName - unique name for the AttributeTypeDef
+     * @return TypeDef object
+     * @throws TypeErrorException - unknown or invalid type
+     */
+    public  AttributeTypeDef  getAttributeTypeDef (String    sourceName,
+                                                   String    attributeTypeDefGUID,
+                                                   String    attributeTypeDefName) throws TypeErrorException
+    {
+        return null;
+    }
+
+
+    /**
+     * Returns an updated TypeDef that has had the supplied patch applied.  It throws an exception if any part of
+     * the patch is incompatible with the original TypeDef.  For example, if there is a mismatch between
+     * the type or version that either represents.
+     *
+     * @param sourceName - source of the TypeDef (used for logging)
+     * @param typeDefPatch - patch to apply
+     * @return updated TypeDef
+     * @throws PatchErrorException - the patch is either badly formatted, or does not apply to the supplied TypeDef
+     */
+    public TypeDef   applyPatch(String sourceName, TypeDefPatch typeDefPatch) throws PatchErrorException
+    {
+        TypeDef    originalTypeDef = null;
+        TypeDef    clonedTypeDef   = null;
+        TypeDef    updatedTypeDef  = null;
+
+        /*
+         * Begin with simple validation of the typeDef patch.
+         */
+        if (typeDefPatch != null)
+        {
+            // TODO patch error
+        }
+
+        long newVersion = typeDefPatch.getUpdateToVersion();
+        if (newVersion <= typeDefPatch.getApplyToVersion())
+        {
+            // TODO PatchError
+        }
+
+        TypeDefPatchAction   patchAction = typeDefPatch.getAction();
+        if (patchAction == null)
+        {
+            // TODO patch error
+        }
+
+        /*
+         * Locate the current definition for the TypeDef
+         */
+        try
+        {
+            originalTypeDef = this.getTypeDef(sourceName, typeDefPatch.getTypeDefGUID(), typeDefPatch.getTypeName());
+        }
+        catch (TypeErrorException   typeError)
+        {
+            // TODO - wrap TypeError in Patch Error
+        }
+
+        /*
+         * Is the version compatible?
+         */
+        if (originalTypeDef.getVersion() != typeDefPatch.getApplyToVersion())
+        {
+            // TODO throw PatchException - incompatible versions
+        }
+
+        /*
+         * OK to perform the update.  Need to create a new TypeDef object.  TypeDef is an abstract class
+         * so need to use the TypeDefCategory to create a new object of the correct type.
+         */
+        TypeDefCategory category = originalTypeDef.getCategory();
+        if (category == null)
+        {
+            // TODO Throw PatchError - base type is messed up
+        }
+
+        try
+        {
+            switch (category)
+            {
+                case ENTITY_DEF:
+                    clonedTypeDef = new EntityDef((EntityDef) originalTypeDef);
+                    break;
+
+                case RELATIONSHIP_DEF:
+                    clonedTypeDef = new RelationshipDef((RelationshipDef) originalTypeDef);
+                    break;
+
+                case CLASSIFICATION_DEF:
+                    clonedTypeDef = new ClassificationDef((ClassificationDef) originalTypeDef);
+                    break;
+            }
+        }
+        catch (ClassCastException  castError)
+        {
+            // TODO Throw PatchError - base type is messed up
+        }
+
+        /*
+         * Now we have a new TypeDef - just need to make the changes.  The Action
+         */
+        if (clonedTypeDef != null)
+        {
+            switch (patchAction)
+            {
+                case ADD_ATTRIBUTES:
+                    updatedTypeDef = this.patchTypeDefAttributes(clonedTypeDef, typeDefPatch.getTypeDefAttributes());
+                    break;
+
+                case ADD_OPTIONS:
+                    updatedTypeDef = this.patchTypeDefNewOptions(clonedTypeDef, typeDefPatch.getTypeDefOptions());
+                    break;
+
+                case UPDATE_OPTIONS:
+                    updatedTypeDef = this.patchTypeDefUpdateOptions(clonedTypeDef, typeDefPatch.getTypeDefOptions());
+                    break;
+
+                case DELETE_OPTIONS:
+                    updatedTypeDef = this.patchTypeDefDeleteOptions(clonedTypeDef, typeDefPatch.getTypeDefOptions());
+                    break;
+
+                case ADD_EXTERNAL_STANDARDS:
+                    updatedTypeDef = this.patchTypeDefAddExternalStandards(clonedTypeDef,
+                                                                           typeDefPatch.getExternalStandardMappings(),
+                                                                           typeDefPatch.getTypeDefAttributes());
+                    break;
+
+                case UPDATE_EXTERNAL_STANDARDS:
+                    updatedTypeDef = this.patchTypeDefUpdateExternalStandards(clonedTypeDef,
+                                                                              typeDefPatch.getExternalStandardMappings(),
+                                                                              typeDefPatch.getTypeDefAttributes());
+                    break;
+
+                case DELETE_EXTERNAL_STANDARDS:
+                    updatedTypeDef = this.patchTypeDefDeleteExternalStandards(clonedTypeDef,
+                                                                              typeDefPatch.getExternalStandardMappings(),
+                                                                              typeDefPatch.getTypeDefAttributes());
+                    break;
+
+                case UPDATE_DESCRIPTIONS:
+                    updatedTypeDef = this.patchTypeDefNewDescriptions(clonedTypeDef,
+                                                                      typeDefPatch.getDescription(),
+                                                                      typeDefPatch.getDescriptionGUID(),
+                                                                      typeDefPatch.getTypeDefAttributes());
+                    break;
+            }
+        }
+
+
+        if (updatedTypeDef != null)
+        {
+            updatedTypeDef.setVersion(typeDefPatch.getUpdateToVersion());
+            updatedTypeDef.setVersionName(typeDefPatch.getNewVersionName());
+        }
+
+        return updatedTypeDef;
+    }
+
+
+    /**
+     * Add the supplied attributes to the properties definition for the cloned typedef.
+     *
+     * @param clonedTypeDef - TypeDef object to update
+     * @param typeDefAttributes - new attributes to add.
+     * @return updated TypeDef
+     * @throws PatchErrorException - problem adding attributes
+     */
+    private TypeDef patchTypeDefAttributes(TypeDef                     clonedTypeDef,
+                                           ArrayList<TypeDefAttribute> typeDefAttributes) throws PatchErrorException
+    {
+        ArrayList<TypeDefAttribute>  propertyDefinitions = clonedTypeDef.getPropertiesDefinition();
+
+        if (propertyDefinitions == null)
+        {
+            propertyDefinitions = new ArrayList<>();
+        }
+
+        for (TypeDefAttribute  newAttribute : typeDefAttributes)
+        {
+            if (newAttribute != null)
+            {
+                String            attributeName = newAttribute.getAttributeName();
+                AttributeTypeDef  attributeType = newAttribute.getAttributeType();
+
+                if ((attributeName != null) && (attributeType != null))
+                {
+                    if (propertyDefinitions.contains(newAttribute))
+                    {
+                        // TODO Patch error - Duplicate Attribute
+                    }
+                    else
+                    {
+                        propertyDefinitions.add(newAttribute);
+                    }
+                }
+                else
+                {
+                    // TODO Patch Error - Invalid Attribute in patch
+                }
+            }
+        }
+
+        if (propertyDefinitions.size() > 0)
+        {
+            clonedTypeDef.setPropertiesDefinition(propertyDefinitions);
+        }
+        else
+        {
+            clonedTypeDef.setPropertiesDefinition(null);
+        }
+
+        return clonedTypeDef;
+    }
+
+
+    /**
+     *
+     * @param clonedTypeDef - TypeDef object to update
+     * @param typeDefOptions - new options to add
+     * @return updated TypeDef
+     * @throws PatchErrorException - problem adding options
+     */
+    private TypeDef patchTypeDefNewOptions(TypeDef             clonedTypeDef,
+                                           Map<String, String> typeDefOptions) throws PatchErrorException
+    {
+        // TODO
+        return null;
+    }
+
+
+    /**
+     *
+     * @param clonedTypeDef - TypeDef object to update
+     * @param typeDefOptions - options to update
+     * @return updated TypeDef
+     * @throws PatchErrorException - problem updating options
+     */
+    private TypeDef patchTypeDefUpdateOptions(TypeDef                clonedTypeDef,
+                                              Map<String, String>    typeDefOptions) throws PatchErrorException
+    {
+        // TODO
+        return null;
+    }
+
+
+    /**
+     *
+     * @param clonedTypeDef - TypeDef object to update
+     * @param typeDefOptions - options to delete
+     * @return updated TypeDef
+     * @throws PatchErrorException - problem deleting options
+     */
+    private TypeDef patchTypeDefDeleteOptions(TypeDef                clonedTypeDef,
+                                              Map<String, String>    typeDefOptions) throws PatchErrorException
+    {
+        // TODO
+        return null;
+    }
+
+
+    /**
+     * Add new mappings to external standards to the TypeDef.
+     *
+     * @param clonedTypeDef - TypeDef object to update
+     * @param externalStandardMappings - new mappings to add
+     * @return updated TypeDef
+     * @throws PatchErrorException - problem adding mapping(s)
+     */
+    private TypeDef patchTypeDefAddExternalStandards(TypeDef                            clonedTypeDef,
+                                                     ArrayList<ExternalStandardMapping> externalStandardMappings,
+                                                     ArrayList<TypeDefAttribute>        typeDefAttributes) throws PatchErrorException
+    {
+        // TODO
+        return null;
+    }
+
+
+    /**
+     * Update the supplied mappings from the TypeDef.
+     *
+     * @param clonedTypeDef - TypeDef object to update
+     * @param externalStandardMappings - mappings to update
+     * @return updated TypeDef
+     * @throws PatchErrorException - problem updating mapping(s)
+     */
+    private TypeDef patchTypeDefUpdateExternalStandards(TypeDef                            clonedTypeDef,
+                                                        ArrayList<ExternalStandardMapping> externalStandardMappings,
+                                                        ArrayList<TypeDefAttribute>        typeDefAttributes) throws PatchErrorException
+    {
+        // TODO
+        return null;
+    }
+
+
+    /**
+     * Delete the supplied mappings from the TypeDef.
+     *
+     * @param clonedTypeDef - TypeDef object to update
+     * @param externalStandardMappings - list of mappings to delete
+     * @return updated TypeDef
+     * @throws PatchErrorException - problem deleting mapping(s)
+     */
+    private TypeDef patchTypeDefDeleteExternalStandards(TypeDef                            clonedTypeDef,
+                                                        ArrayList<ExternalStandardMapping> externalStandardMappings,
+                                                        ArrayList<TypeDefAttribute>        typeDefAttributes) throws PatchErrorException
+    {
+        // TODO
+        return null;
+    }
+
+
+    /**
+     * Update the descriptions for the TypeDef or any of its attributes.  If the description values are null, they are
+     * not changes in the TypeDef.  This means there is no way to clear a description - just update it for a better one.
+     *
+     * @param clonedTypeDef - TypeDef object to update
+     * @param description - new description
+     * @param descriptionGUID - new unique identifier for glossary term that provides detailed description of TypeDef
+     * @return updated TypeDef
+     * @throws PatchErrorException - problem adding new description
+     */
+    private TypeDef patchTypeDefNewDescriptions(TypeDef                     clonedTypeDef,
+                                                String                      description,
+                                                String                      descriptionGUID,
+                                                ArrayList<TypeDefAttribute> typeDefAttributes) throws PatchErrorException
+    {
+        if (description != null)
+        {
+            clonedTypeDef.setDescription(description);
+        }
+        if (descriptionGUID != null)
+        {
+            clonedTypeDef.setDescriptionGUID(descriptionGUID);
+        }
+
+        if (typeDefAttributes != null)
+        {
+            ArrayList<TypeDefAttribute>  propertiesDefinition = clonedTypeDef.getPropertiesDefinition();
+
+            if (propertiesDefinition == null)
+            {
+                // TODO throw patch error - attempting to Patch TypeDef with no properties
+            }
+
+            for (TypeDefAttribute  patchTypeDefAttribute : typeDefAttributes)
+            {
+                if (patchTypeDefAttribute != null)
+                {
+                    String     patchTypeDefAttributeName = patchTypeDefAttribute.getAttributeName();
+
+                    if (patchTypeDefAttributeName != null)
+                    {
+                        for (TypeDefAttribute  existingProperty : propertiesDefinition)
+                        {
+                            if (existingProperty != null)
+                            {
+                                if (patchTypeDefAttributeName.equals(existingProperty.getAttributeName()))
+                                {
+
+                                }
+                            }
+                            else
+                            {
+                                // TODO throw Patch Error because basic Type is messed up
+                            }
+                        }
+                    }
+                    else
+                    {
+                        //  TODO throw Patch Error null attribute name
+                    }
+                }
+                else
+                {
+                    // TODO throw Patch Error null attribute included
+                }
+            }
+        }
+
+        return clonedTypeDef;
+    }
+
+    /*
+     * =======================
+     * OMRSTypeDefValidator
+     */
+
+    /**
+     * Return a summary list of the TypeDefs supported by the local metadata repository.  This is
+     * broadcast to the other servers/repositories in the cohort during the membership registration exchanges
+     * managed by the cohort registries.
+     *
+     * @return TypeDefSummary list
+     */
+    public ArrayList<TypeDefSummary> getLocalTypeDefs()
+    {
+        ArrayList<TypeDefSummary> activeTypeDefSummaries = null;
+
+        if (activeTypes != null)
+        {
+            activeTypeDefSummaries = new ArrayList<>();
+
+            for (TypeDef activeType : activeTypes.values())
+            {
+                activeTypeDefSummaries.add(activeType);
+            }
+        }
+
+        return activeTypeDefSummaries;
+    }
+
+
+    /**
+     * Return a boolean flag indicating whether the list of TypeDefs passed are compatible with the
+     * local metadata repository.  A true response means it is ok; false means conflicts have been found.
+     *
+     * A valid TypeDef is one that:
+     * <ul>
+     *     <li>
+     *         Matches name, GUID and version to a TypeDef in the local repository, or
+     *     </li>
+     *     <li>
+     *         Is not defined in the local repository.
+     *     </li>
+     * </ul>
+     *
+     * @param sourceName - source of the request (used for logging)
+     * @param typeDefSummaries - list of summary information about the TypeDefs.
+     */
+    public void validateAgainstLocalTypeDefs(String sourceName, ArrayList<TypeDefSummary> typeDefSummaries)
+    {
+
+        // TODO if invalid typeDefs are detected, they are logged and TypeDef conflict messages are sent to
+        // the typeDefEventProcessor methods to distributed
+    }
+
+
+    /**
+     * Return a boolean flag indicating whether the list of TypeDefs passed are compatible with the
+     * all known typedefs.
+     *
+     * A valid TypeDef is one that matches name, GUID and version to the full list of TypeDefs.
+     * If a new TypeDef is present, it is added to the enterprise list.
+     *
+     * @param sourceName - source of the TypeDef (used for logging)
+     * @param typeDefs - list of TypeDefs.
+     * @return boolean flag
+     */
+    public boolean   validateEnterpriseTypeDefs(String sourceName, ArrayList<TypeDef> typeDefs)
+    {
+        return true;
+    }
+
+    /**
+     * Return boolean indicating whether the TypeDef is one of the standard open metadata types.
+     *
+     * @param sourceName - source of the TypeDef (used for logging)
+     * @param typeDefGUID - unique identifier of the type
+     * @param typeDefName - unique name of the type
+     * @return boolean result
+     */
+    public boolean isOpenType(String sourceName, String   typeDefGUID, String   typeDefName)
+    {
+        if (isKnownType(sourceName, typeDefGUID, typeDefName))
+        {
+            TypeDef typeDef = knownTypes.get(typeDefName);
+
+            if (typeDef == null)
+            {
+                return false;
+            }
+
+            if (openTypesOriginGUID != null)
+            {
+                if (openTypesOriginGUID.equals(typeDef.getOrigin()))
+                {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+
+    /**
+     * Return boolean indicating whether the TypeDef is known, either as an open type, or one defined
+     * by one or more of the members of the cohort.
+     *
+     * @param sourceName - source of the TypeDef (used for logging)
+     * @param typeDefGUID - unique identifier of the type
+     * @param typeDefName - unique name of the type
+     * @return boolean result
+     */
+    public boolean isKnownType(String sourceName, String   typeDefGUID, String   typeDefName)
+    {
+        if (typeDefName == null)
+        {
+            return false;
+        }
+
+        TypeDef  typeDef = knownTypes.get(typeDefName);
+
+        if (typeDef == null)
+        {
+            return false;
+        }
+
+        if (typeDefGUID != null)
+        {
+            if (typeDefGUID.equals(typeDef.getGUID()))
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+        else
+        {
+            return true;
+        }
+    }
+
+
+    /**
+     * Return boolean indicating whether the TypeDef is in use in the repository.
+     *
+     * @param sourceName - source of the TypeDef (used for logging)
+     * @param typeDefGUID - unique identifier of the type
+     * @param typeDefName - unique name of the type
+     * @return boolean result
+     */
+    public boolean isActiveType(String sourceName, String   typeDefGUID, String   typeDefName)
+    {
+        if (typeDefName == null)
+        {
+            return false;
+        }
+
+        TypeDef  typeDef = activeTypes.get(typeDefName);
+
+        if (typeDef == null)
+        {
+            return false;
+        }
+
+        if (typeDefGUID != null)
+        {
+            if (typeDefGUID.equals(typeDef.getGUID()))
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+        else
+        {
+            return true;
+        }
+    }
+
+    /**
+     * Return boolean indicating whether the TypeDef identifiers are valid or not.
+     *
+     * @param sourceName - source of the TypeDef (used for logging)
+     * @param typeDefGUID - unique identifier of the TypeDef
+     * @param typeDefName - unique name of the TypeDef
+     * @return boolean result
+     */
+    public boolean validTypeId(String          sourceName,
+                               String          typeDefGUID,
+                               String          typeDefName)
+    {
+        if (typeDefName == null)
+        {
+            // TODO Log error
+            return false;
+        }
+
+        if (typeDefGUID == null)
+        {
+            // TODO Log warning - probably caused by local repository connector not setting up GUID properly
+            return false;
+        }
+
+        TypeDef typeDef = knownTypes.get(typeDefName);
+
+        if (typeDef == null)
+        {
+            // TODO log unknown type
+            return false;
+        }
+
+        if (! typeDefGUID.equals(typeDef.getGUID()))
+        {
+            // TODO log type mismatch
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Return boolean indicating whether the TypeDef identifiers are valid or not.
+     *
+     * @param sourceName - source of the TypeDef (used for logging)
+     * @param typeDefGUID - unique identifier of the TypeDef
+     * @param typeDefName - unique name of the TypeDef
+     * @return boolean result
+     */
+    public boolean validTypeId(String          sourceName,
+                               String          typeDefGUID,
+                               String          typeDefName,
+                               TypeDefCategory category)
+    {
+        if (! validTypeId(sourceName, typeDefGUID, typeDefName))
+        {
+            /*
+             * Error already logged.
+             */
+            return false;
+        }
+
+        TypeDef          typeDef = knownTypes.get(typeDefName);
+        TypeDefCategory  knownTypeDefCategory = typeDef.getCategory();
+
+        if (knownTypeDefCategory == null)
+        {
+            // TODO log messed up cache
+            return false;
+        }
+
+        if (category.getTypeCode() != knownTypeDefCategory.getTypeCode())
+        {
+            // TODO log type mismatch
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Return boolean indicating whether the TypeDef identifiers are valid or not.
+     *
+     * @param sourceName - source of the TypeDef (used for logging)
+     * @param typeDefGUID - unique identifier of the TypeDef
+     * @param typeDefName - unique name of the TypeDef
+     * @param typeDefVersion - versionName of the type
+     * @param typeDefCategory - category of the instance described by this TypeDef.
+     * @return boolean result
+     */
+    public boolean validTypeId(String          sourceName,
+                               String          typeDefGUID,
+                               String          typeDefName,
+                               long            typeDefVersion,
+                               TypeDefCategory typeDefCategory)
+    {
+        if (! validTypeId(sourceName, typeDefGUID, typeDefName, typeDefCategory))
+        {
+            return false;
+        }
+
+        TypeDef   typeDef = knownTypes.get(typeDefName);
+
+        if (typeDef == null)
+        {
+            // Log logic error
+            return false;
+        }
+
+        if (typeDef.getVersion() != typeDefVersion)
+        {
+            // TODO log warning to say version mismatch
+            return false;
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Return boolean indicating whether the supplied TypeDef is valid or not.
+     *
+     * @param sourceName - source of the TypeDef (used for logging)
+     * @param typeDef - TypeDef to test
+     * @return boolean result
+     */
+    public boolean validTypeDef(String         sourceName,
+                                TypeDef        typeDef)
+    {
+        if (typeDef == null)
+        {
+            // TODO log null TypeDef
+            return false;
+        }
+
+        if (validTypeId(sourceName,
+                        typeDef.getGUID(),
+                        typeDef.getName(),
+                        typeDef.getVersion(),
+                        typeDef.getCategory()))
+        {
+            return true;
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+
+    /**
+     * Return boolean indicating whether the supplied TypeDefSummary is valid or not.
+     *
+     * @param sourceName - source of the TypeDefSummary (used for logging)
+     * @param typeDefSummary - TypeDefSummary to test.
+     * @return boolean result.
+     */
+    public boolean validTypeDefSummary(String                sourceName,
+                                       TypeDefSummary        typeDefSummary)
+    {
+        if (typeDefSummary != null)
+        {
+            if (validTypeId(sourceName,
+                            typeDefSummary.getGUID(),
+                            typeDefSummary.getName(),
+                            typeDefSummary.getVersion(),
+                            typeDefSummary.getCategory()))
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+
+    /*
+     * ===========================
+     * OMRSTypeDefEventProcessor
+     */
+
+
+    /**
+     * A new TypeDef has been defined either in an archive, or in another member of the cohort.
+     *
+     * This new TypeDef can be added to the repository if it does not clash with an existing typeDef and the local
+     * repository supports dynamic type definitions.
+     *
+     * @param sourceName - name of the source of the event.  It may be the cohort name for incoming events or the
+     *                   local repository, or event mapper name.
+     * @param originatorMetadataCollectionId - unique identifier for the metadata collection hosted by the server that
+     *                                       sent the event.
+     * @param originatorServerName - name of the server that the event came from.
+     * @param originatorServerType - type of server that the event came from.
+     * @param originatorOrganizationName - name of the organization that owns the server that sent the event.
+     * @param typeDef - details of the new TypeDef
+     */
+    public void processNewTypeDefEvent(String       sourceName,
+                                       String       originatorMetadataCollectionId,
+                                       String       originatorServerName,
+                                       String       originatorServerType,
+                                       String       originatorOrganizationName,
+                                       TypeDef      typeDef)
+    {
+
+
+        OMRSMetadataCollection metadataCollection = null;
+
+        if (localRepositoryConnector != null)
+        {
+            localRepositoryConnector.getMetadataCollection();
+        }
+
+        if (metadataCollection != null)
+        {
+            try
+            {
+                /*
+                 * VerifyTypeDef returns true if the typeDef is known and matches the supplied definition.
+                 * It returns false if the type is supportable but has not yet been defined.
+                 * It throws TypeDefNotSupportedException if the typeDef is not supported and can not
+                 * be dynamically defined by the local repository.
+                 */
+                if (! metadataCollection.verifyTypeDef(null, typeDef))
+                {
+                    metadataCollection.addTypeDef(null, typeDef);
+
+                    /*
+                     * Update the active TypeDefs as this new TypeDef has been accepted by the local repository.
+                     */
+                    activeTypes.put(typeDef.getName(), typeDef);
+                }
+            }
+            catch (TypeDefNotSupportedException fixedTypeSystemResponse)
+            {
+
+
+                if (log.isDebugEnabled())
+                {
+                    log.debug("TypeDef not added because repository does not support dynamic type definitions", typeDef);
+                    log.debug("TypeDefNotSupportedException:", fixedTypeSystemResponse);
+
+                }
+            }
+            catch (RepositoryErrorException error)
+            {
+                // TODO log an error to say that the repository is not available
+
+                if (log.isDebugEnabled())
+                {
+                    log.debug("TypeDef not added because repository is not available", typeDef);
+                    log.debug("RepositoryErrorException:", error);
+
+                }
+            }
+            catch (TypeDefConflictException error)
+            {
+                // TODO log an error to say that the TypeDef conflicts with a TypeDef already stored.
+
+                if (log.isDebugEnabled())
+                {
+                    log.debug("TypeDef not added because it conflicts with another TypeDef already in the repository", typeDef);
+                    log.debug("TypeDefConflictException:", error);
+                }
+            }
+            catch (InvalidTypeDefException error)
+            {
+                // TODO log an error to say that the TypeDef contains bad values.
+
+                if (log.isDebugEnabled())
+                {
+                    log.debug("TypeDef not added because repository is not available", typeDef);
+                    log.debug("InvalidTypeDefException:", error);
+                }
+            }
+            catch (TypeDefKnownException error)
+            {
+                // TODO log an error to say that a logic error has occurred
+
+                if (log.isDebugEnabled())
+                {
+                    log.debug("TypeDef not added because repository has a logic error", typeDef);
+                    log.debug("TypeDefKnownException:", error);
+
+                }
+            }
+            catch (Throwable  error)
+            {
+                // TODO log an error to say that an unexpected error has occurred
+
+                if (log.isDebugEnabled())
+                {
+                    log.debug("TypeDef not added because repository has an unexpected error", typeDef);
+                    log.debug("Throwable:", error);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * A new AttributeTypeDef has been defined in an open metadata repository.
+     *
+     * @param sourceName - name of the source of the event.  It may be the cohort name for incoming events or the
+     *                   local repository, or event mapper name.
+     * @param originatorMetadataCollectionId - unique identifier for the metadata collection hosted by the server that
+     *                                       sent the event.
+     * @param originatorServerName - name of the server that the event came from.
+     * @param originatorServerType - type of server that the event came from.
+     * @param originatorOrganizationName - name of the organization that owns the server that sent the event.
+     * @param attributeTypeDef - details of the new AttributeTypeDef.
+     */
+    public void processNewAttributeTypeDefEvent(String           sourceName,
+                                                String           originatorMetadataCollectionId,
+                                                String           originatorServerName,
+                                                String           originatorServerType,
+                                                String           originatorOrganizationName,
+                                                AttributeTypeDef attributeTypeDef)
+    {
+        // TODO
+    }
+
+
+    /**
+     * An existing TypeDef has been updated in a remote metadata repository.
+     *
+     * @param sourceName - name of the source of the event.  It may be the cohort name for incoming events or the
+     *                   local repository, or event mapper name.
+     * @param originatorMetadataCollectionId - unique identifier for the metadata collection hosted by the server that
+     *                                       sent the event.
+     * @param originatorServerName - name of the server that the event came from.
+     * @param originatorServerType - type of server that the event came from.
+     * @param originatorOrganizationName - name of the organization that owns the server that sent the event.
+     * @param typeDefPatch - details of the new versionName of the TypeDef
+     */
+    public void processUpdatedTypeDefEvent(String       sourceName,
+                                           String       originatorMetadataCollectionId,
+                                           String       originatorServerName,
+                                           String       originatorServerType,
+                                           String       originatorOrganizationName,
+                                           TypeDefPatch typeDefPatch)
+    {
+        OMRSMetadataCollection metadataCollection = localRepositoryConnector.getMetadataCollection();
+
+        if (metadataCollection != null)
+        {
+            try
+            {
+                TypeDef updatedTypeDef = metadataCollection.updateTypeDef(null, typeDefPatch);
+
+                if (log.isDebugEnabled())
+                {
+                    log.debug("Patch successfully applied", updatedTypeDef);
+                }
+            }
+            catch (RepositoryErrorException  error)
+            {
+                // TODO log an error to say that the repository is not available
+
+                if (log.isDebugEnabled())
+                {
+                    log.debug("Patch not applied because repository is not available", typeDefPatch);
+                }
+            }
+            catch (TypeDefNotKnownException  error)
+            {
+                // TODO log an error to say that the TypeDef is not known
+
+                if (log.isDebugEnabled())
+                {
+                    log.debug("Patch not applied because TypeDef does not exist", typeDefPatch);
+                    log.debug("TypeDefNotKnownException:", error);
+                }
+            }
+            catch (PatchErrorException  error)
+            {
+                // TODO log an error to say that the TypeDef patch is invalid
+
+                if (log.isDebugEnabled())
+                {
+                    log.debug("Patch not applied because it is invalid", typeDefPatch);
+                    log.debug("PatchErrorException:", error);
+                }
+            }
+            catch (Throwable error)
+            {
+                // TODO log a generic error
+
+                if (log.isDebugEnabled())
+                {
+                    log.debug("Patch not applied because of an error", typeDefPatch);
+                    log.debug("Throwable:", error);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * An existing TypeDef has been deleted in a remote metadata repository.  Both the name and the
+     * GUID are provided to ensure the right TypeDef is deleted in other cohort member repositories.
+     *
+     * @param sourceName - name of the source of the event.  It may be the cohort name for incoming events or the
+     *                   local repository, or event mapper name.
+     * @param originatorMetadataCollectionId - unique identifier for the metadata collection hosted by the server that
+     *                                       sent the event.
+     * @param originatorServerName - name of the server that the event came from.
+     * @param originatorServerType - type of server that the event came from.
+     * @param originatorOrganizationName - name of the organization that owns the server that sent the event.
+     * @param typeDefGUID - unique identifier of the TypeDef
+     * @param typeDefName - unique name of the TypeDef
+     */
+    public void processDeletedTypeDefEvent(String      sourceName,
+                                           String      originatorMetadataCollectionId,
+                                           String      originatorServerName,
+                                           String      originatorServerType,
+                                           String      originatorOrganizationName,
+                                           String      typeDefGUID,
+                                           String      typeDefName)
+    {
+        // TODO
+    }
+
+
+    /**
+     * An existing AttributeTypeDef has been deleted in an open metadata repository.  Both the name and the
+     * GUID are provided to ensure the right AttributeTypeDef is deleted in other cohort member repositories.
+     *
+     * @param sourceName - name of the source of the event.  It may be the cohort name for incoming events or the
+     *                   local repository, or event mapper name.
+     * @param originatorMetadataCollectionId - unique identifier for the metadata collection hosted by the server that
+     *                                       sent the event.
+     * @param originatorServerName - name of the server that the event came from.
+     * @param originatorServerType - type of server that the event came from.
+     * @param originatorOrganizationName - name of the organization that owns the server that sent the event.
+     * @param attributeTypeDefGUID - unique identifier of the AttributeTypeDef
+     * @param attributeTypeDefName - unique name of the AttributeTypeDef
+     */
+    public void processDeletedAttributeTypeDefEvent(String      sourceName,
+                                                    String      originatorMetadataCollectionId,
+                                                    String      originatorServerName,
+                                                    String      originatorServerType,
+                                                    String      originatorOrganizationName,
+                                                    String      attributeTypeDefGUID,
+                                                    String      attributeTypeDefName)
+    {
+        // TODO
+    }
+
+
+    /**
+     * Process an event that changes either the name or guid of a TypeDef.  It is resolving a Conflicting TypeDef Error.
+     *
+     * @param sourceName - name of the source of the event.  It may be the cohort name for incoming events or the
+     *                   local repository, or event mapper name.
+     * @param originatorMetadataCollectionId - unique identifier for the metadata collection hosted by the server that
+     *                                       sent the event.
+     * @param originatorServerName - name of the server that the event came from.
+     * @param originatorServerType - type of server that the event came from.
+     * @param originatorOrganizationName - name of the organization that owns the server that sent the event.
+     * @param originalTypeDefSummary - details of the original TypeDef
+     * @param typeDef - updated TypeDef with new identifiers inside.
+     */
+    public void processReIdentifiedTypeDefEvent(String         sourceName,
+                                                String         originatorMetadataCollectionId,
+                                                String         originatorServerName,
+                                                String         originatorServerType,
+                                                String         originatorOrganizationName,
+                                                TypeDefSummary originalTypeDefSummary,
+                                                TypeDef        typeDef)
+    {
+
+    }
+
+
+    /**
+     * Process an event that changes either the name or guid of an AttributeTypeDef.
+     * It is resolving a Conflicting AttributeTypeDef Error.
+     *
+     * @param sourceName - name of the source of the event.  It may be the cohort name for incoming events or the
+     *                   local repository, or event mapper name.
+     * @param originatorMetadataCollectionId - unique identifier for the metadata collection hosted by the server that
+     *                                       sent the event.
+     * @param originatorServerName - name of the server that the event came from.
+     * @param originatorServerType - type of server that the event came from.
+     * @param originatorOrganizationName - name of the organization that owns the server that sent the event.
+     * @param originalAttributeTypeDef - description of original AttributeTypeDef
+     * @param attributeTypeDef - updated AttributeTypeDef with new identifiers inside.
+     */
+    public void processReIdentifiedAttributeTypeDefEvent(String           sourceName,
+                                                         String           originatorMetadataCollectionId,
+                                                         String           originatorServerName,
+                                                         String           originatorServerType,
+                                                         String           originatorOrganizationName,
+                                                         AttributeTypeDef originalAttributeTypeDef,
+                                                         AttributeTypeDef attributeTypeDef)
+    {
+        // TODO
+    }
+
+
+    /**
+     * Process a detected conflict in type definitions (TypeDefs) used in the cohort.
+     *
+     * @param sourceName - name of the source of the event.  It may be the cohort name for incoming events or the
+     *                   local repository, or event mapper name.
+     * @param originatorMetadataCollectionId - unique identifier for the metadata collection hosted by the server that
+     *                                       sent the event.
+     * @param originatorServerName - name of the server that the event came from.
+     * @param originatorServerType - type of server that the event came from.
+     * @param originatorOrganizationName - name of the organization that owns the server that sent the event.
+     * @param originatorTypeDefSummary - details of the TypeDef in the event originator
+     * @param otherMetadataCollectionId - the metadataCollection using the conflicting TypeDef
+     * @param conflictingTypeDefSummary - the details of the TypeDef in the other metadata collection
+     * @param errorMessage - details of the error that occurs when the connection is used.
+     */
+    public void processTypeDefConflictEvent(String         sourceName,
+                                            String         originatorMetadataCollectionId,
+                                            String         originatorServerName,
+                                            String         originatorServerType,
+                                            String         originatorOrganizationName,
+                                            TypeDefSummary originatorTypeDefSummary,
+                                            String         otherMetadataCollectionId,
+                                            TypeDefSummary conflictingTypeDefSummary,
+                                            String         errorMessage)
+    {
+        // TODO
+    }
+
+
+    /**
+     * Process a detected conflict in the attribute type definitions (AttributeTypeDefs) used in the cohort.
+     *
+     * @param sourceName - name of the source of the event.  It may be the cohort name for incoming events or the
+     *                   local repository, or event mapper name.
+     * @param originatorMetadataCollectionId - unique identifier for the metadata collection hosted by the server that
+     *                                       sent the event.
+     * @param originatorServerName - name of the server that the event came from.
+     * @param originatorServerType - type of server that the event came from.
+     * @param originatorOrganizationName - name of the organization that owns the server that sent the event.
+     * @param originatorAttributeTypeDef- description of the AttributeTypeDef in the event originator.
+     * @param otherMetadataCollectionId - the metadataCollection using the conflicting AttributeTypeDef.
+     * @param conflictingAttributeTypeDef - description of the AttributeTypeDef in the other metadata collection.
+     * @param errorMessage - details of the error that occurs when the connection is used.
+     */
+    public void processAttributeTypeDefConflictEvent(String           sourceName,
+                                                     String           originatorMetadataCollectionId,
+                                                     String           originatorServerName,
+                                                     String           originatorServerType,
+                                                     String           originatorOrganizationName,
+                                                     AttributeTypeDef originatorAttributeTypeDef,
+                                                     String           otherMetadataCollectionId,
+                                                     AttributeTypeDef conflictingAttributeTypeDef,
+                                                     String           errorMessage)
+    {
+        // TODO
+    }
+
+
+    /**
+     * A TypeDef from another member in the cohort is at a different versionName than the local repository.  This may
+     * create some inconsistencies in the different copies of instances of this type in different members of the
+     * cohort.  The recommended action is to update all TypeDefs to the latest versionName.
+     *
+     * @param sourceName - name of the source of the event.  It may be the cohort name for incoming events or the
+     *                   local repository, or event mapper name.
+     * @param originatorMetadataCollectionId - unique identifier for the metadata collection hosted by the server that
+     *                                       sent the event.
+     * @param originatorServerName - name of the server that the event came from.
+     * @param originatorServerType - type of server that the event came from.
+     * @param originatorOrganizationName - name of the organization that owns the server that sent the event.
+     * @param targetMetadataCollectionId - identifier of the metadata collection that is reporting a TypeDef at a
+     *                                   different level to the local repository.
+     * @param targetTypeDefSummary - details of the target TypeDef
+     * @param otherTypeDef - details of the TypeDef in the local repository.
+     */
+    public void processTypeDefPatchMismatchEvent(String         sourceName,
+                                                 String         originatorMetadataCollectionId,
+                                                 String         originatorServerName,
+                                                 String         originatorServerType,
+                                                 String         originatorOrganizationName,
+                                                 String         targetMetadataCollectionId,
+                                                 TypeDefSummary targetTypeDefSummary,
+                                                 TypeDef        otherTypeDef,
+                                                 String         errorMessage)
+    {
+
+    }
+
+
+    /*
+     * =====================
+     * OMRSInstanceValidator
+     */
+
+    /**
+     * Test that the supplied entity is valid.
+     *
+     * @param sourceName - source of the entity (used for logging)
+     * @param entity - entity to test
+     * @return boolean result
+     */
+    public boolean validEntity(String       sourceName,
+                               EntityDetail entity)
+    {
+        if (entity == null)
+        {
+            // TODO log null entity
+            return false;
+        }
+
+        InstanceType instanceType = entity.getType();
+
+        if (instanceType == null)
+        {
+            // TODO log null type
+            return false;
+        }
+
+        if (! validInstanceId(sourceName,
+                              instanceType.getTypeDefGUID(),
+                              instanceType.getTypeDefName(),
+                              instanceType.getTypeDefCategory(),
+                              entity.getGUID()))
+        {
+            /*
+             * Error messages already logged.
+             */
+            return false;
+        }
+
+        String          homeMetadataCollectionId = entity.getMetadataCollectionId();
+
+        if (homeMetadataCollectionId == null)
+        {
+            // TODO log error
+            return false;
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Test that the supplied relationship is valid.
+     *
+     * @param sourceName - source of the relationship (used for logging)
+     * @param relationship - relationship to test
+     * @return boolean result
+     */
+    public boolean validRelationship(String       sourceName,
+                                     Relationship relationship)
+    {
+        if (relationship == null)
+        {
+            // TODO log null relationship
+            return false;
+        }
+
+        InstanceType instanceType = relationship.getType();
+
+        if (instanceType == null)
+        {
+            // TODO log null type
+            return false;
+        }
+
+        if (! validInstanceId(sourceName,
+                              instanceType.getTypeDefGUID(),
+                              instanceType.getTypeDefName(),
+                              instanceType.getTypeDefCategory(),
+                              relationship.getGUID()))
+        {
+            /*
+             * Error messages already logged.
+             */
+            return false;
+        }
+
+        String          homeMetadataCollectionId = relationship.getMetadataCollectionId();
+
+        if (homeMetadataCollectionId == null)
+        {
+            // TODO log error
+            return false;
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Verify that the identifiers for an instance are correct.
+     *
+     * @param sourceName - source of the instance (used for logging)
+     * @param typeDefGUID - unique identifier for the type.
+     * @param typeDefName - unique name for the type.
+     * @param category - expected category of the instance.
+     * @param instanceGUID - unique identifier for the instance.
+     * @return boolean indicating whether the identifiers are ok.
+     */
+    public boolean validInstanceId(String           sourceName,
+                                   String           typeDefGUID,
+                                   String           typeDefName,
+                                   TypeDefCategory  category,
+                                   String           instanceGUID)
+    {
+        if (instanceGUID == null)
+        {
+            // TODO - log null guid
+            return false;
+        }
+
+        if (! validTypeId(sourceName,
+                          typeDefGUID,
+                          typeDefName,
+                          category))
+        {
+            /*
+             * Error messages already logged
+             */
+            return false;
+        }
+
+        return true;
+    }
+}