Example #1
0
        /// <summary>
        /// get the work item type mapping entry
        /// </summary>
        /// <param name="sourceSide"></param>
        /// <param name="sourceType"></param>
        /// <returns></returns>
        public HashSet <string> GetMappedTypeNames(SourceSideTypeEnum sourceSide)
        {
            AddMissingDefaultMap();

            HashSet <string> mappedTypeNames = new HashSet <string>();

            foreach (WorkItemTypeMappingElement map in this.WorkItemType)
            {
                if (sourceSide == SourceSideTypeEnum.Left)
                {
                    if (map.LeftWorkItemTypeName.Equals(WitMappingConfigVocab.Any, System.StringComparison.OrdinalIgnoreCase))
                    {
                        mappedTypeNames.Clear();
                        mappedTypeNames.Add(WitMappingConfigVocab.Any);
                        break;
                    }
                    mappedTypeNames.Add(map.LeftWorkItemTypeName);
                }
                else
                {
                    if (map.RightWorkItemTypeName.Equals(WitMappingConfigVocab.Any, System.StringComparison.OrdinalIgnoreCase))
                    {
                        mappedTypeNames.Clear();
                        mappedTypeNames.Add(WitMappingConfigVocab.Any);
                        break;
                    }
                    mappedTypeNames.Add(map.RightWorkItemTypeName);
                }
            }

            return(mappedTypeNames);
        }
        /// <summary>
        /// Get the mapped field entry given a specific migration source Unique Id and source field name
        /// </summary>
        /// <param name="sourceSide"></param>
        /// <param name="fieldName"></param>
        /// <returns></returns>
        public MappedField GetMappedFieldEntry(SourceSideTypeEnum sourceSide, string fieldName)
        {
            MappedField retVal = null;

            foreach (MappedField mappedField in this.MappedField)
            {
                if (mappedField.MapFromSide == sourceSide)
                {
                    if (fieldName == (sourceSide == SourceSideTypeEnum.Left ? mappedField.LeftName : mappedField.RightName))
                    {
                        retVal = mappedField;
                        break;
                    }
                    else
                    {
                        if (sourceSide == SourceSideTypeEnum.Left &&
                            mappedField.LeftName == WitMappingConfigVocab.Any &&
                            retVal == null)
                        {
                            retVal = mappedField;
                        }
                        else if (sourceSide == SourceSideTypeEnum.Right &&
                                 mappedField.RightName == WitMappingConfigVocab.Any &&
                                 retVal == null)
                        {
                            retVal = mappedField;
                        }
                        continue;
                    }
                }
            }

            return(retVal);
        }
        /// <summary>
        /// Given the migration source side and field reference name, gets the UserIdentityField configuration element.
        /// </summary>
        /// <param name="fromSide"></param>
        /// <param name="srcFieldRefName"></param>
        /// <returns>The UserIdFieldElement for the subject field; NULL if no configuration is present.</returns>
        public UserIdFieldElement GetUserIdField(
            SourceSideTypeEnum fromSide,
            string srcFieldRefName)
        {
            NotifyingCollection <UserIdFieldElement> userIdFields;

            switch (fromSide)
            {
            case SourceSideTypeEnum.Left:
                userIdFields = UserIdentityFields.LeftUserIdentityFields.UserIdField;
                break;

            case SourceSideTypeEnum.Right:
                userIdFields = UserIdentityFields.RightUserIdentityFields.UserIdField;
                break;

            default:
                return(null);
            }

            foreach (var userIdField in userIdFields)
            {
                if (userIdField.FieldReferenceName.Equals(srcFieldRefName, StringComparison.OrdinalIgnoreCase))
                {
                    return(userIdField);
                }
            }

            return(null);
        }
Example #4
0
        private bool IsTargetFieldMapped(SourceSideTypeEnum mapFromSide, string targetField)
        {
            if (string.IsNullOrEmpty(targetField))
            {
                // if target field is string.Empty, we will drop the source field after translation
                // thus, it is legal that there are multiple source field to string.Empty in the config
                return(false);
            }

            if (IsFieldInCachedTargetField(mapFromSide, targetField))
            {
                return(true);
            }

            if (mapFromSide == SourceSideTypeEnum.Any)
            {
                if (IsFieldInCachedTargetField(SourceSideTypeEnum.Left, targetField) ||
                    IsFieldInCachedTargetField(SourceSideTypeEnum.Right, targetField))
                {
                    return(true);
                }
            }

            return(false);
        }
        /// <summary>
        /// Try getting a mapped value given a migration source unique Id and the value to be mapped.
        /// </summary>
        /// <param name="fromSide">Left or Right of the migration source in the session configuration</param>
        /// <param name="sourceFieldValue">Value before the mapping rule is applied</param>
        /// <param name="valueMapName"></param>
        /// <param name="descriptionDocRootNode">The document that contains all the field information in a particular revision</param>
        /// <param name="mappedValue">Value after the mapping rule is applied</param>
        /// <returns>True if a mapping rule is applied; FALSE otherwise</returns>
        private bool GetMappedFieldValue(
            SourceSideTypeEnum fromSide,
            string sourceFieldValue,
            string valueMapName,
            XmlElement descriptionDocRootNode,
            out string mappedValue)
        {
            TraceManager.TraceVerbose("Getting mapped field value of '{0}' in Value Map '{1}'",
                                      sourceFieldValue ?? string.Empty, valueMapName ?? string.Empty);
            ValueMap valueMapEntry = null;

            foreach (ValueMap valueMap in m_session.WITCustomSetting.ValueMaps.ValueMap)
            {
                if (valueMap.name == valueMapName)
                {
                    valueMapEntry = valueMap;
                    break;
                }
            }

            if (null != valueMapEntry)
            {
                TraceManager.TraceVerbose("Applying mapped field value of '{0}' in Value Map '{1}'",
                                          sourceFieldValue ?? string.Empty, valueMapName ?? string.Empty);
                return(valueMapEntry.TryGetMappedValue(fromSide, sourceFieldValue, descriptionDocRootNode, out mappedValue));
            }
            else
            {
                TraceManager.TraceVerbose("Cannot find Value Map '{0}'", valueMapName ?? string.Empty);
                mappedValue = sourceFieldValue;
                return(false);
            }
        }
Example #6
0
        private void UpdateMappedFieldCache(SourceSideTypeEnum sourceSideTypeEnum, string leftName, string rightName)
        {
            switch (sourceSideTypeEnum)
            {
            case SourceSideTypeEnum.Left:
                if (!m_perDirectionSourceMappedFields[sourceSideTypeEnum].Contains(leftName))
                {
                    m_perDirectionSourceMappedFields[sourceSideTypeEnum].Add(leftName);
                }
                break;

            case SourceSideTypeEnum.Right:
                if (!m_perDirectionSourceMappedFields[sourceSideTypeEnum].Contains(rightName))
                {
                    m_perDirectionSourceMappedFields[sourceSideTypeEnum].Add(rightName);
                }
                break;

            case SourceSideTypeEnum.Any:
                if (!m_perDirectionSourceMappedFields[SourceSideTypeEnum.Left].Contains(rightName))
                {
                    m_perDirectionSourceMappedFields[SourceSideTypeEnum.Left].Add(rightName);
                }
                if (!m_perDirectionSourceMappedFields[SourceSideTypeEnum.Right].Contains(leftName))
                {
                    m_perDirectionSourceMappedFields[SourceSideTypeEnum.Right].Add(leftName);
                }
                break;

            default:
                throw new InvalidOperationException();
            }
        }
        private string MapUserIdentity(
            FieldMap fieldMap,
            SourceSideTypeEnum fromSide,
            string srcFieldRefName,
            string tgtFieldRefName,
            string srcFieldValue)
        {
            RichIdentity srcUserId = new RichIdentity();

            UserIdFieldElement userIdField = fieldMap.GetUserIdField(fromSide, srcFieldRefName);

            srcUserId[userIdField.UserIdPropertyName] = srcFieldValue;

            RichIdentity mappedUserId;

            if (UserIdLookupService.TryLookup(srcUserId, m_contexts[fromSide], out mappedUserId))
            {
                SourceSideTypeEnum toSide       = (fromSide == SourceSideTypeEnum.Left) ? SourceSideTypeEnum.Right : SourceSideTypeEnum.Left;
                UserIdFieldElement tgtUserField = fieldMap.GetUserIdField(toSide, tgtFieldRefName);
                if (null != tgtUserField)
                {
                    return(mappedUserId[tgtUserField.UserIdPropertyName]);
                }
                else
                {
                    return(srcFieldValue);
                }
            }
            else
            {
                return(srcFieldValue);
            }
        }
        private void MapFieldValue(
            FieldMap fieldMap,
            SourceSideTypeEnum fromSide,
            XmlNode fieldColumn,
            string srcFieldRefName,
            string tgtFieldRefName,
            string srcFieldValue,
            string valueMapName,
            XmlElement descriptionDocRootNode)
        {
            string mappedValue;

            if (!string.IsNullOrEmpty(valueMapName) && GetMappedFieldValue(fromSide, srcFieldValue, valueMapName, descriptionDocRootNode, out mappedValue))
            {
                // do nothing, we have the mappedValue set
            }
            else if (UserIdLookupService.IsConfigured && fieldMap.IsUserIdField(fromSide, srcFieldRefName))
            {
                // try user id lookup
                mappedValue = MapUserIdentity(fieldMap, fromSide, srcFieldRefName, tgtFieldRefName, srcFieldValue);
            }
            else
            {
                // in other cases, just use the srcFieldValue
                mappedValue = srcFieldValue;
            }

            fieldColumn.FirstChild.InnerText = mappedValue;
        }
Example #9
0
        private bool IsFieldInCachedSourceFields(SourceSideTypeEnum mapFromSide, string targetField)
        {
            if (m_perDirectionSourceMappedFields.ContainsKey(mapFromSide) &&
                m_perDirectionSourceMappedFields[mapFromSide].Contains(targetField))
            {
                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Get the mapped field name from a particular side of a MappedField entry
        /// </summary>
        /// <param name="sourceSide"></param>
        /// <param name="mappedFieldEntry"></param>
        /// <returns>The name of the mapped field</returns>
        public string GetMappedFieldName(
            SourceSideTypeEnum sourceSide,
            string sourceFieldName,
            MappedField mappedFieldEntry)
        {
            if (null == mappedFieldEntry)
            {
                throw new ArgumentNullException();
            }

            return((sourceSide == SourceSideTypeEnum.Left)
                ? (mappedFieldEntry.RightName == WitMappingConfigVocab.Any ? sourceFieldName : mappedFieldEntry.RightName)
                : (mappedFieldEntry.LeftName == WitMappingConfigVocab.Any ? sourceFieldName : mappedFieldEntry.LeftName));
        }
        /// <summary>
        /// Get all the "missing" field entries given a specific migration source Unique Id
        /// </summary>
        /// <param name="sourceSide"></param>
        /// <returns></returns>
        public ReadOnlyCollection <MappedField> GetMissingFieldEntries(SourceSideTypeEnum sourceSide)
        {
            List <MappedField> fields = new List <MappedField>();

            foreach (MappedField mappedField in this.MappedField)
            {
                string mapFromFieldName = (sourceSide == SourceSideTypeEnum.Left ? mappedField.LeftName : mappedField.RightName);
                if (mappedField.MapFromSide == sourceSide &&
                    WitMappingConfigVocab.MissingField.Equals(mapFromFieldName, System.StringComparison.OrdinalIgnoreCase))
                {
                    fields.Add(mappedField);
                }
            }

            return(fields.AsReadOnly());
        }
Example #12
0
        /// <summary>
        /// Perform the adapter-specific initialization
        /// </summary>
        public virtual void InitializeClient(MigrationSource migrationSource)
        {
            TfsTeamProjectCollection tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(migrationSource.ServerUrl));

            tfs.Authenticate();

            m_workItemStore = (WorkItemStore)tfs.GetService(typeof(WorkItemStore));

            m_projectName = migrationSource.SourceIdentifier;

            m_migrationSourceGuid = new Guid(migrationSource.InternalUniqueId);
            if (m_migrationSourceGuid.Equals(m_session.LeftMigrationSourceUniqueId))
            {
                m_sourceSide = SourceSideTypeEnum.Left;
            }
            else
            {
                m_sourceSide = SourceSideTypeEnum.Right;
            }
        }
        /// <summary>
        /// get the mapped work item type name
        /// </summary>
        /// <param name="sourceSide"></param>
        /// <param name="sourceWorkItemType"></param>
        /// <param name="mappingEntry"></param>
        /// <returns>the mapped work item type; the sourceType if wildcard character
        /// "*" is used; NULL if none is applicable</returns>
        /// <remarks>
        /// WorkItemTypes element must have at least one entry (WorkItemType).
        /// The following line shows where the wildcard characters can be used:
        /// &lt;WorkItemType LeftWorkItemTypeName="*" RightWorkItemTypeName="*" fieldMap="@@ALL@@" /&gt;
        /// - "*" means ANY in above context.
        /// - "@@ALL@@" means "map all fields" in above context.
        /// </remarks>
        public string GetMappedType(
            SourceSideTypeEnum sourceSide,
            string sourceWorkItemType,
            WorkItemTypeMappingElement mappingEntry)
        {
            if (null == mappingEntry)
            {
                throw new ArgumentNullException();
            }

            string retVal = (sourceSide == SourceSideTypeEnum.Left)
                            ? mappingEntry.RightWorkItemTypeName
                            : mappingEntry.LeftWorkItemTypeName;

            if (retVal.Equals(WitMappingConfigVocab.Any, System.StringComparison.OrdinalIgnoreCase))
            {
                retVal = sourceWorkItemType;
            }

            return(retVal);
        }
        public List <string> GetReferencedFieldReferenceNames(SourceSideTypeEnum sourceSide)
        {
            if (!m_perSideReferencedFieldNames.ContainsKey(sourceSide))
            {
                List <string> referencedFields = new List <string>();
                foreach (var fieldMap in this.FieldMaps.FieldMap)
                {
                    foreach (var aggregationGroup in fieldMap.AggregatedFields.FieldsAggregationGroup)
                    {
                        if (aggregationGroup.MapFromSide == sourceSide)
                        {
                            foreach (var f in aggregationGroup.SourceField)
                            {
                                if (!referencedFields.Contains(f.SourceFieldName, StringComparer.OrdinalIgnoreCase))
                                {
                                    referencedFields.Add(f.SourceFieldName);
                                }
                            }
                        }
                    }
                }

                foreach (var valueMap in this.ValueMaps.ValueMap)
                {
                    foreach (var mappedValue in valueMap.Value)
                    {
                        if (mappedValue.When != null && mappedValue.When.ConditionalSrcFieldName != null &&
                            !mappedValue.When.ConditionalSrcFieldName.Equals(WitMappingConfigVocab.Any) &&
                            !referencedFields.Contains(mappedValue.When.ConditionalSrcFieldName, StringComparer.OrdinalIgnoreCase))
                        {
                            referencedFields.Add(mappedValue.When.ConditionalSrcFieldName);
                        }
                    }
                }

                m_perSideReferencedFieldNames.Add(sourceSide, referencedFields);
            }

            return(m_perSideReferencedFieldNames[sourceSide]);
        }
        private void MapOwnerUserId(
            XmlElement rootNode,
            SourceSideTypeEnum fromSide)
        {
            if (!UserIdLookupService.IsConfigured)
            {
                return;
            }

            var authorAttr = rootNode.Attributes["Author"];

            if (authorAttr == null || string.IsNullOrEmpty(authorAttr.Value))
            {
                return;
            }

            RichIdentity srcUserId = new RichIdentity();
            var          authorUserIdPropertyAttr = rootNode.Attributes[Constants.WITAuthorUserIdPropertyName];
            string       authorUserIdProperty;

            if (authorUserIdPropertyAttr == null || string.IsNullOrEmpty(authorUserIdPropertyAttr.Value))
            {
                authorUserIdProperty = "DisplayName";
            }
            else
            {
                authorUserIdProperty = authorUserIdPropertyAttr.Value;
            }

            srcUserId[authorUserIdProperty] = authorAttr.Value;

            RichIdentity mappedUserId;

            if (UserIdLookupService.TryLookup(srcUserId, m_contexts[fromSide], out mappedUserId))
            {
                authorAttr.Value = mappedUserId.DisplayName;
            }
        }
        /// <summary>
        /// get the work item type mapping entry
        /// </summary>
        /// <param name="sourceSide"></param>
        /// <param name="sourceType"></param>
        /// <returns></returns>
        public WorkItemTypeMappingElement GetMappingEntry(SourceSideTypeEnum sourceSide, string sourceType)
        {
            AddMissingDefaultMap();

            WorkItemTypeMappingElement retVal = null;

            foreach (WorkItemTypeMappingElement map in this.WorkItemType)
            {
                switch (sourceSide)
                {
                case SourceSideTypeEnum.Left:
                    if (map.LeftWorkItemTypeName == sourceType)
                    {
                        return(map);
                    }
                    else if (map.LeftWorkItemTypeName.Equals(WitMappingConfigVocab.Any, System.StringComparison.OrdinalIgnoreCase))
                    {
                        retVal = map;
                    }
                    break;

                case SourceSideTypeEnum.Right:
                    if (map.RightWorkItemTypeName == sourceType)
                    {
                        return(map);
                    }
                    else if (map.RightWorkItemTypeName.Equals(WitMappingConfigVocab.Any, System.StringComparison.OrdinalIgnoreCase))
                    {
                        retVal = map;
                    }
                    break;
                }
            }

            return(retVal);
        }
Example #17
0
        private bool IsSourceFieldMapped(SourceSideTypeEnum mapFromSide, string sourceField)
        {
            if (string.IsNullOrEmpty(sourceField))
            {
                // if source field is string.Empty, it is allowed but won't be applied to any field
                return(false);
            }

            if (IsFieldInCachedSourceFields(mapFromSide, sourceField))
            {
                return(true);
            }

            if (mapFromSide == SourceSideTypeEnum.Any)
            {
                if (IsFieldInCachedSourceFields(SourceSideTypeEnum.Left, sourceField) ||
                    IsFieldInCachedSourceFields(SourceSideTypeEnum.Right, sourceField))
                {
                    return(true);
                }
            }

            return(false);
        }
 /// <summary>
 /// Given the migration source side and field reference name, tells if it is a UserIdentity field.
 /// </summary>
 /// <param name="fromSide"></param>
 /// <param name="srcFieldRefName"></param>
 /// <returns></returns>
 public bool IsUserIdField(
     SourceSideTypeEnum fromSide,
     string srcFieldRefName)
 {
     return(null != GetUserIdField(fromSide, srcFieldRefName));
 }
        /// <summary>
        ///
        /// </summary>
        /// <param name="sourceSide"></param>
        /// <param name="conditionalMaps"></param>
        /// <param name="descriptionDocRootNode"></param>
        /// <param name="mappedValue"></param>
        /// <returns>True if a mapping rule is applied; FALSE otherwise</returns>
        /// <remarks>
        /// The following evaluation precedence is honored:
        ///     map v1 => v2, when F.value = f
        ///     map *  => v2, when F.value = f
        ///     map v1 => v2, when F.value = *
        ///     map *  => v2, when F.value = *
        /// </remarks>
        private bool TryConditionalMap(
            SourceSideTypeEnum sourceSide,
            List <Value> conditionalMaps,
            XmlElement descriptionDocRootNode,
            ref string mappedValue)
        {
            Value explicitCondExplicitValue = null;
            Value explicteCondWildcardValue = null;
            Value wildcardCondExplicitValue = null;
            Value wildcardCondWildcardValue = null;

            foreach (Value vMap in conditionalMaps)
            {
                string srcFldRefNameInCond = vMap.When.ConditionalSrcFieldName;
                string srcFldValueInCond   = vMap.When.ConditionalSrcFieldValue;

                XmlNode srcFldColNode = descriptionDocRootNode.SelectSingleNode(
                    string.Format("/WorkItemChanges/Columns/Column[@ReferenceName='{0}']", srcFldRefNameInCond));

                if (null != srcFldColNode)
                {
                    if (srcFldValueInCond.Equals(WitMappingConfigVocab.Any))
                    {
                        if (WitMappingConfigVocab.Any == (sourceSide == SourceSideTypeEnum.Left ? vMap.LeftValue : vMap.RightValue))
                        {
                            // map *  => v2, when F.value = *
                            wildcardCondWildcardValue = vMap;
                        }
                        else
                        {
                            // map v1 => v2, when F.value = *
                            wildcardCondExplicitValue = vMap;
                        }
                    }
                    else if (srcFldValueInCond.Equals(srcFldColNode.FirstChild.InnerText))
                    {
                        if (WitMappingConfigVocab.Any == (sourceSide == SourceSideTypeEnum.Left ? vMap.LeftValue : vMap.RightValue))
                        {
                            // map *  => v2, when F.value = f
                            explicteCondWildcardValue = vMap;
                        }
                        else
                        {
                            // map v1 => v2, when F.value = f
                            explicitCondExplicitValue = vMap;
                            break;
                        }
                    }
                }
            }

            bool retVal = false;

            if (explicitCondExplicitValue != null)
            {
                mappedValue = ApplyValueMap(explicitCondExplicitValue, sourceSide);
                retVal      = true;
            }
            else if (explicteCondWildcardValue != null)
            {
                mappedValue = ApplyValueMap(explicteCondWildcardValue, sourceSide);
                retVal      = true;
            }
            else if (wildcardCondExplicitValue != null)
            {
                mappedValue = ApplyValueMap(wildcardCondExplicitValue, sourceSide);
                retVal      = true;
            }
            else if (wildcardCondWildcardValue != null)
            {
                mappedValue = ApplyValueMap(wildcardCondWildcardValue, sourceSide);
                retVal      = true;
            }

            return(retVal);
        }
 private string ApplyValueMap(Value valueMap, SourceSideTypeEnum sourceSide)
 {
     return((sourceSide == SourceSideTypeEnum.Left ? valueMap.RightValue : valueMap.LeftValue) ?? string.Empty);
 }
        ///// <summary>
        ///// Get a mapped value given a migration source unique Id and the value to be mapped.
        ///// </summary>
        ///// <param name="sourceSide"></param>
        ///// <param name="sourceValue"></param>
        ///// <returns></returns>
        ///// <remarks>
        ///// The following evaluation precedence is honored:
        /////     map v1 => v2, when F.value = f
        /////     map *  => v2, when F.value = f
        /////     map v1 => v2, when F.value = *
        /////     map *  => v2, when F.value = *
        /////     map v1 => v2
        /////     map *  => v2
        ///// </remarks>


        /// <summary>
        /// Try getting a mapped value given a migration source unique Id and the value to be mapped.
        /// </summary>
        /// <param name="sourceSide">Left or Right of the migration source in the session configuration</param>
        /// <param name="sourceValue">Value before the mapping rule is applied</param>
        /// <param name="descriptionDocRootNode">The document that contains all the field information in a particular revision</param>
        /// <param name="mappedValue">Value after the mapping rule is applied</param>
        /// <returns>True if a mapping rule is applied; FALSE otherwise</returns>
        /// <remarks>
        /// The following evaluation precedence is honored:
        ///     map v1 => v2, when F.value = f
        ///     map *  => v2, when F.value = f
        ///     map v1 => v2, when F.value = *
        ///     map *  => v2, when F.value = *
        ///     map v1 => v2
        ///     map *  => v2
        /// </remarks>
        public bool TryGetMappedValue(
            SourceSideTypeEnum sourceSide,
            string sourceValue,
            XmlElement descriptionDocRootNode,
            out string mappedValue)
        {
            mappedValue = sourceValue;

            #region find applicable rules
            List <Value> conditionalMaps = new List <Value>();
            Value        explicitMap     = null;
            Value        wildCardMap     = null;
            foreach (Value valuePair in this.Value)
            {
                if (sourceValue == (sourceSide == SourceSideTypeEnum.Left ? valuePair.LeftValue : valuePair.RightValue))
                {
                    if (null == valuePair.When ||
                        (string.IsNullOrEmpty(valuePair.When.ConditionalSrcFieldName) && string.IsNullOrEmpty(valuePair.When.ConditionalSrcFieldValue)))
                    {
                        if (null == explicitMap)
                        {
                            explicitMap = valuePair;
                        }
                        else
                        {
                            Trace.TraceWarning("There are multiple value maps mapping from the same source value '{0}'.", sourceValue ?? string.Empty);
                        }
                    }
                    else
                    {
                        conditionalMaps.Add(valuePair);
                    }
                }
                else if (WitMappingConfigVocab.Any == (sourceSide == SourceSideTypeEnum.Left ? valuePair.LeftValue : valuePair.RightValue))
                {
                    if (null == valuePair.When ||
                        (string.IsNullOrEmpty(valuePair.When.ConditionalSrcFieldName) && string.IsNullOrEmpty(valuePair.When.ConditionalSrcFieldValue)))
                    {
                        if (null == wildCardMap)
                        {
                            wildCardMap = valuePair;
                        }
                        else
                        {
                            Trace.TraceWarning("There are multiple wildcard-character entries in the value map '{0}'.", this.name ?? string.Empty);
                        }
                    }
                    else
                    {
                        conditionalMaps.Add(valuePair);
                    }
                }
            }
            #endregion

            #region try applying rules
            bool mappingRuleApplied = TryConditionalMap(sourceSide, conditionalMaps, descriptionDocRootNode, ref mappedValue);
            if (!mappingRuleApplied)
            {
                if (null != explicitMap)
                {
                    mappedValue        = (sourceSide == SourceSideTypeEnum.Left ? explicitMap.RightValue : explicitMap.LeftValue);
                    mappingRuleApplied = true;
                }
                else if (null != wildCardMap)
                {
                    mappedValue        = (sourceSide == SourceSideTypeEnum.Left ? wildCardMap.RightValue : wildCardMap.LeftValue);
                    mappingRuleApplied = true;
                }
            }
            #endregion

            if (mappingRuleApplied && mappedValue.Equals(WitMappingConfigVocab.Any))
            {
                // mapping * to * semantically means copy source value to target
                mappedValue = sourceValue;
            }
            return(mappingRuleApplied);
        }
        public void MapWorkItemTypeFieldValues(string itemId, XmlDocument workItemDescriptionDocument, Guid sourceId)
        {
            XmlDocument copy = new XmlDocument();

            copy.LoadXml(workItemDescriptionDocument.OuterXml);

            XmlElement rootNode = workItemDescriptionDocument.DocumentElement;

            if (null == rootNode)
            {
                throw new MigrationException(MigrationToolkitResources.InvalideChangeActionDescription, itemId);
            }

            bool isLeft = DecideSidenessInConfig(sourceId, m_session);
            SourceSideTypeEnum sourceSide = isLeft ? SourceSideTypeEnum.Left : SourceSideTypeEnum.Right;

            MapOwnerUserId(rootNode, sourceSide);

            #region Map work item type

            string sourceWorkItemType = rootNode.Attributes["WorkItemType"].Value;
            WorkItemTypeMappingElement typeMapEntry =
                m_session.WITCustomSetting.WorkItemTypes.GetMappingEntry(sourceSide, sourceWorkItemType);

            if (null == typeMapEntry)
            {
                throw new UnmappedWorkItemTypeException(sourceWorkItemType);
            }

            string targetWorkItemType = m_session.WITCustomSetting.WorkItemTypes.GetMappedType(
                sourceSide,
                sourceWorkItemType,
                typeMapEntry);

            rootNode.SetAttribute("WorkItemType", targetWorkItemType);

            #endregion

            if (null == typeMapEntry || /* backward compatibility */
                string.IsNullOrEmpty(typeMapEntry.fieldMap) || /* backward compatibility */
                typeMapEntry.fieldMap.Equals(WitMappingConfigVocab.All, StringComparison.OrdinalIgnoreCase))
            {
                XmlNode columnsNode = rootNode.SelectSingleNode("/WorkItemChanges/Columns");
                if (null == columnsNode)
                {
                    throw new MigrationException(MigrationToolkitResources.InvalideChangeActionDescription, itemId);
                }
                XmlNodeList columns = rootNode.SelectNodes("/WorkItemChanges/Columns/Column");
                if (null == columns)
                {
                    throw new MigrationException(MigrationToolkitResources.InvalideChangeActionDescription, itemId);
                }

                List <XmlNode> fieldsToExclude = new List <XmlNode>();
                foreach (XmlNode fieldColumn in columnsNode)
                {
                    if (IsSkippingField(fieldColumn))
                    {
                        fieldsToExclude.Add(fieldColumn);
                    }
                }

                foreach (XmlNode excludedField in fieldsToExclude)
                {
                    excludedField.ParentNode.RemoveChild(excludedField);
                }
                fieldsToExclude.Clear();
            }
            else
            {
                #region look up the field map entry to use

                FieldMap fieldMapEntry = null;
                foreach (FieldMap fieldMap in m_session.WITCustomSetting.FieldMaps.FieldMap)
                {
                    if (fieldMap.name == typeMapEntry.fieldMap)
                    {
                        fieldMapEntry = fieldMap;
                        break;
                    }
                }

                #endregion

                #region Map field and value

                if (null != fieldMapEntry)
                {
                    XmlNode columnsNode = rootNode.SelectSingleNode("/WorkItemChanges/Columns");
                    if (null == columnsNode)
                    {
                        throw new MigrationException(MigrationToolkitResources.InvalideChangeActionDescription, itemId);
                    }

                    #region map aggregated fields
                    List <string> aggregatedFields = new List <string>(); // store the aggregated fields so that we won't delete them later
                    if (fieldMapEntry.AggregatedFields.FieldsAggregationGroup.Count() > 0)
                    {
                        foreach (var fieldsGroup in fieldMapEntry.AggregatedFields.FieldsAggregationGroup)
                        {
                            if (fieldsGroup.MapFromSide != sourceSide || fieldsGroup.SourceField.Count == 0)
                            {
                                continue;
                            }

                            bool canUseMappingConfig = true;

                            // apply value map to the aggregated fields and identify the field columns
                            // Note:
                            // 1. Aggregated fields may appear in normal field maps
                            // 2. If an aggregated field does not appear in normal field map,
                            //    the field will be dropped after the translation
                            // 3. If a field appear in both aggregated and normal field mapping,
                            //    it may use different value maps
                            foreach (SourceField srcField in fieldsGroup.SourceField)
                            {
                                XmlNode srcFieldCol = rootNode.SelectSingleNode(
                                    string.Format("/WorkItemChanges/Columns/Column[@ReferenceName='{0}']", srcField.SourceFieldName));

                                if (null != srcFieldCol)
                                {
                                    // map field value and cache the result
                                    srcField.FieldColumnNode = srcFieldCol;

                                    string mappedValue;
                                    if (GetMappedFieldValue(sourceSide, srcFieldCol.FirstChild.InnerText, srcField.valueMap, copy.DocumentElement, out mappedValue))
                                    {
                                        srcField.MappedValue = mappedValue;
                                    }
                                    else
                                    {
                                        srcField.MappedValue = srcFieldCol.FirstChild.InnerText;
                                    }
                                }
                                else
                                {
                                    // one of the aggregated field is not present in the WIT description document
                                    TraceManager.TraceInformation(
                                        "Aggregating field '{0}' is not in the WIT update document of Change Action {1}'",
                                        srcField.SourceFieldName,
                                        itemId);

                                    canUseMappingConfig = false;
                                    break;
                                }
                            }

                            if (!canUseMappingConfig)
                            {
                                continue;
                            }

                            string[] srcFieldValues = new string[fieldsGroup.SourceField.Count];
                            foreach (SourceField srcField in fieldsGroup.SourceField)
                            {
                                if (srcField.Index >= 0 && srcField.Index < srcFieldValues.Length)
                                {
                                    srcFieldValues[srcField.Index] = srcField.MappedValue ?? string.Empty;
                                }
                                else
                                {
                                    TraceManager.TraceError(
                                        "Source aggregation field '{0}' has a wrong index of '{1}' in the configuration.",
                                        srcField.SourceFieldName ?? string.Empty, srcField.Index.ToString());
                                }
                            }

                            for (int i = 0; i < srcFieldValues.Length; ++i)
                            {
                                if (srcFieldValues[i] == null)
                                {
                                    TraceManager.TraceError(
                                        "Aggregated field format '{0}' has NULL value at index '{1}'.",
                                        fieldsGroup.Format, i.ToString());
                                    canUseMappingConfig = false;
                                }
                            }

                            if (!canUseMappingConfig)
                            {
                                continue;
                            }

                            try
                            {
                                string aggregatedFieldName  = fieldsGroup.TargetFieldName;
                                string aggregatedFieldValue = string.Format(
                                    System.Globalization.CultureInfo.InvariantCulture,
                                    fieldsGroup.Format, srcFieldValues);

                                // first, try looking for the field in the document (the field may exist on source side
                                // and included in the delta document)
                                XmlNode aggregatedFieldInDoc = rootNode.SelectSingleNode(
                                    string.Format("/WorkItemChanges/Columns/Column[@ReferenceName='{0}']", aggregatedFieldName));

                                if (null == aggregatedFieldInDoc)
                                {
                                    XmlElement aggregatedFieldCol = columnsNode.OwnerDocument.CreateElement("Column");
                                    aggregatedFieldCol.SetAttribute("ReferenceName", aggregatedFieldName);
                                    aggregatedFieldCol.SetAttribute("Type", string.Empty);
                                    aggregatedFieldCol.SetAttribute("DisplayName", string.Empty);
                                    columnsNode.AppendChild(aggregatedFieldCol);
                                    XmlElement v = columnsNode.OwnerDocument.CreateElement("Value");
                                    v.InnerText = aggregatedFieldValue;
                                    aggregatedFieldCol.AppendChild(v);
                                }
                                else
                                {
                                    aggregatedFieldInDoc.FirstChild.InnerText = aggregatedFieldValue;
                                }

                                aggregatedFields.Add(aggregatedFieldName);
                            }
                            catch (System.FormatException formatException)
                            {
                                TraceManager.TraceException(formatException);
                            }
                        }
                    }
                    #endregion

                    // map field and values
                    XmlNodeList columns = rootNode.SelectNodes("/WorkItemChanges/Columns/Column");
                    if (null == columns)
                    {
                        throw new MigrationException(MigrationToolkitResources.InvalideChangeActionDescription, itemId);
                    }

                    List <XmlNode> fieldsToExclude = new List <XmlNode>();
                    foreach (XmlNode fieldColumn in columns)
                    {
                        string srcFieldRefName = fieldColumn.Attributes["ReferenceName"].Value;
                        string srcFieldValue   = fieldColumn.FirstChild.InnerText;

                        MappedField mappedFieldEntry = fieldMapEntry.MappedFields.GetMappedFieldEntry(
                            sourceSide, srcFieldRefName);
                        if (null == mappedFieldEntry)
                        {
                            if (!aggregatedFields.Contains(srcFieldRefName, StringComparer.OrdinalIgnoreCase))
                            {
                                // record the unmapped fields and delete them after the field/value mapping is applied
                                // aggregated fields are added by us and are target-specific - they shouldn't be deleted
                                fieldsToExclude.Add(fieldColumn);
                            }
                            continue;
                        }
                        else
                        {
                            string mapFromField = (isLeft ? mappedFieldEntry.LeftName : mappedFieldEntry.RightName);
                            if (mapFromField.Equals(WitMappingConfigVocab.Any, StringComparison.OrdinalIgnoreCase))
                            {
                                if (IsSkippingField(fieldColumn))
                                {
                                    fieldsToExclude.Add(fieldColumn);
                                }
                            }
                        }

                        string tgtFieldRefName = fieldMapEntry.MappedFields.GetMappedFieldName(sourceSide, srcFieldRefName, mappedFieldEntry);
                        if (string.IsNullOrEmpty(tgtFieldRefName))
                        {
                            // record the fields that are mapped to "", semantically the field is excluded on target side
                            fieldsToExclude.Add(fieldColumn);
                            continue;
                        }

                        MapFieldValue(fieldMapEntry, sourceSide, fieldColumn, srcFieldRefName, tgtFieldRefName, srcFieldValue, mappedFieldEntry.valueMap, copy.DocumentElement);
                        fieldColumn.Attributes["ReferenceName"].Value = tgtFieldRefName;
                    }

                    // delete the unmapped fields
                    foreach (XmlNode unmappedField in fieldsToExclude)
                    {
                        unmappedField.ParentNode.RemoveChild(unmappedField);
                    }
                    fieldsToExclude.Clear();
                    aggregatedFields.Clear();

                    // apply missing field & default values
                    var missingFieldMappings = fieldMapEntry.MappedFields.GetMissingFieldEntries(sourceSide);
                    foreach (MappedField mappedFieldEntry in missingFieldMappings)
                    {
                        if (null == mappedFieldEntry)
                        {
                            continue;
                        }

                        string     missingFieldName = (sourceSide == SourceSideTypeEnum.Left ? mappedFieldEntry.RightName : mappedFieldEntry.LeftName);
                        XmlElement missingField     = columnsNode.OwnerDocument.CreateElement("Column");
                        missingField.SetAttribute("ReferenceName", missingFieldName);
                        missingField.SetAttribute("Type", string.Empty);
                        missingField.SetAttribute("DisplayName", string.Empty);
                        columnsNode.AppendChild(missingField);

                        // note missing fields do not have "from" value, hence User Id lookup is not needed.
                        string missingFieldValue = string.Empty;
                        if (!string.IsNullOrEmpty(mappedFieldEntry.valueMap))
                        {
                            string mappedValue;
                            if (GetMappedFieldValue(sourceSide, missingFieldValue, mappedFieldEntry.valueMap, copy.DocumentElement, out mappedValue))
                            {
                                missingFieldValue = mappedValue;
                            }
                            else
                            {
                                // use the source value when there is no value map, i.e.
                                // missingFieldValue = missingFieldValue;
                            }
                        }

                        XmlElement v = columnsNode.OwnerDocument.CreateElement("Value");
                        v.InnerText = missingFieldValue;
                        missingField.AppendChild(v);
                    }
                }

                #endregion
            }
        }