private void SetRecordEditable(OAdEntity cqEntity)
        {
            string       entityDefName       = CQWrapper.GetEntityDefName(cqEntity);
            OAdEntityDef entityDef           = CQWrapper.GetEntityDef(m_userSession, entityDefName);
            string       modifyActionDefName = FindCQActionDefName(entityDef, CQConstants.ACTION_MODIFY);

            // open the record with the modify action
            CQWrapper.EditEntity(m_userSession, cqEntity, modifyActionDefName);
        }
Beispiel #2
0
        public static string[] FindAllChangeActionNamesByType(
            Session userSession,
            OAdEntity entity,
            int changeType)
        {
            // find the entity type
            OAdEntityDef entityDef = CQWrapper.GetEntityDef(userSession, CQWrapper.GetEntityDefName(entity));

            // find the MODIFY action def name to open the record
            object[] actionDefNames      = CQWrapper.GetActionDefNames(entityDef) as object[];
            string[] allValidActionNames = CQUtilityMethods.FindActionNameByType(entityDef, actionDefNames, changeType);

            return(allValidActionNames);
        }
        public static List <LinkType> ExtractSupportedLinkTypes(
            Session session,
            string hostRecordType)
        {
            List <LinkType> retval = new List <LinkType>();

            OAdEntityDef aEntityDef = CQWrapper.GetEntityDef(session, hostRecordType);

            object[] fieldDefNameObjs = CQWrapper.GetFieldDefNames(aEntityDef) as object[];

            foreach (object fieldDefNameObj in fieldDefNameObjs)
            {
                string fieldDefName = fieldDefNameObj as string;
                int    fieldDefType = CQWrapper.GetFieldDefType(aEntityDef, fieldDefName);

                if (fieldDefType == CQConstants.FIELD_REFERENCE)
                {
                    retval.Add(new ClearQuestReferenceFieldLinkTypeBase(hostRecordType, fieldDefName));
                }
            }

            return(retval);
        }
Beispiel #4
0
        private void ComputeDeltaPerRecord(
            OAdEntity aRecord)
        {
            OAdEntityDef aEntityDef       = CQWrapper.GetEntityDef(m_userSession, CQWrapper.GetEntityDefName(aRecord));
            string       recordDispName   = CQWrapper.GetEntityDisplayName(aRecord);
            string       recordEntDefName = CQWrapper.GetEntityDefName(aRecord);

            #region process history

            bool recordContentIsModified = false;
            bool maybeNewRecord          = false;
            Dictionary <string, List <ClearQuestRecordItem> > historyDelta = new Dictionary <string, List <ClearQuestRecordItem> >();
            Dictionary <string, int> perHistoryFieldLastIndex = new Dictionary <string, int>();   // needed for updating processed delta

            // find all history fields
            OAdHistoryFields aHistFields = CQWrapper.GetHistoryFields(aRecord);
            int  historyFldCount         = CQWrapper.HistoryFieldsCount(aHistFields);
            bool containsNewHistory      = false;
            for (int histFldIndex = 0; histFldIndex < historyFldCount; histFldIndex++)
            {
                object          ob               = (object)histFldIndex;
                OAdHistoryField aHistoryField    = CQWrapper.HistoryFieldsItem(aHistFields, ref ob);
                string          historyFieldName = CQWrapper.GetHistoryFieldName(aHistoryField);

                // find last processed history entry for this history field
                string lookupItemId   = CQDeltaComputationProgressLookupService.CreateHistoryItemId(recordEntDefName, recordDispName, historyFieldName);
                int    startHistIndex = 1 + DeltaComputeProgressService.GetLastProcessedItemVersion(lookupItemId);

                // find all history in a particular history field
                int historyCount = CQWrapper.HistoryFieldHistoriesCount(aHistoryField);
                for (int histIndex = startHistIndex; histIndex < historyCount; histIndex++)
                {
                    object     obHistIndex = (object)histIndex;
                    OAdHistory aHistory    = CQWrapper.HistoryFieldHistoriesItem(aHistoryField, ref obHistIndex);
                    CQHistory  cqHistory   = new CQHistory(aHistory);

                    CQMigrationItem migrationItem = new CQHistoryMigrationItem(recordDispName, historyFieldName, histIndex);

                    if (TranslationService.IsSyncGeneratedItemVersion(ClearQuestRecordItem.GetMigrationRecordId(recordEntDefName, recordDispName),
                                                                      migrationItem.MigrationItemVersion,
                                                                      m_configurationService.SourceId))
                    {
                        continue;
                    }

                    if (histIndex == 0)
                    {
                        maybeNewRecord = true;
                    }

                    // add unprocessed history fields for processing
                    if (!historyDelta.ContainsKey(historyFieldName))
                    {
                        historyDelta.Add(historyFieldName, new List <ClearQuestRecordItem>(historyCount));
                    }
                    historyDelta[aHistoryField.fieldname].Add(new ClearQuestRecordItem(aRecord, aHistory, historyFieldName, histIndex.ToString()));
                    containsNewHistory = true;

                    // based on action type, we decide whether content change is needed
                    int actionType = CQWrapper.GetActionDefType(aEntityDef, cqHistory.Action);
                    switch (actionType)
                    {
                    case CQConstants.ACTION_SUBMIT:
                        break;

                    case CQConstants.ACTION_MODIFY:
                        recordContentIsModified = true;
                        break;

                    case CQConstants.ACTION_CHANGE:
                        break;

                    case CQConstants.ACTION_DUPLICATE:
                        break;

                    case CQConstants.ACTION_UNDUPLICATE:
                        break;

                    case CQConstants.ACTION_IMPORT:
                        break;

                    case CQConstants.ACTION_DELETE:
                        TraceManager.TraceInformation(ClearQuestResource.ClearQuest_Msg_RecordDeleted, recordEntDefName, recordDispName);
                        break;

                    case CQConstants.ACTION_BASE:
                        break;

                    case CQConstants.ACTION_RECORD_SCRIPT_ALIAS:
                        break;
                    }
                }

                perHistoryFieldLastIndex.Add(historyFieldName, historyCount - 1);
            }

            #endregion

            #region generate delta for content and history

            if (maybeNewRecord || recordContentIsModified)
            {
                // the first revision, i.e. "Submit", of a CQ record is always hard-coded to be '1'
                CQMigrationItem contentMigrationAction = new CQMigrationItem(recordDispName, ClearQuestRecordItem.NewRecordVersion);
                bool            isNewRecord            = false;
                if (maybeNewRecord)
                {
                    isNewRecord = !(DeltaComputeProgressService.IsMigrationItemProcessed(recordDispName, ClearQuestRecordItem.NewRecordVersionValue));
                }

                if (!isNewRecord)
                {
                    // all subsequent record "MODIFICATIONs" are hard-coded to be "update@<Now.Ticks>"
                    contentMigrationAction.MigrationItemVersion = ClearQuestRecordItem.RecordUpdateVersion + "@" + DateTime.Now.Ticks;
                }

                ClearQuestRecordItem recordContentItem = new ClearQuestRecordItem(aRecord, contentMigrationAction.MigrationItemVersion);
                recordContentItem.CQSession = m_userSession;
                recordContentItem.Version   = contentMigrationAction.MigrationItemVersion;
                ChangeGroup contentChangeGroup = recordContentItem.CreateChangeGroup(
                    m_changeGroupService, m_migrationContext, isNewRecord && m_isLastRevisionAutoCorrectionEnabled);
                contentChangeGroup.Save();

                if (isNewRecord && !containsNewHistory)
                {
                    DeltaComputeProgressService.UpdateCache(recordDispName, ClearQuestRecordItem.NewRecordVersionValue);
                }
            }

            var lastHistoryRecordItem = historyDelta[historyDelta.Keys.Last()].Last();
            foreach (string histFieldName in historyDelta.Keys)
            {
                foreach (ClearQuestRecordItem recordHistItem in historyDelta[histFieldName])
                {
                    recordHistItem.CQSession = m_userSession;
                    ChangeGroup changeGroup = recordHistItem.CreateChangeGroup(
                        m_changeGroupService,
                        m_migrationContext,
                        (CQStringComparer.FieldName.Equals(recordHistItem.HistoryFieldName, lastHistoryRecordItem.HistoryFieldName) &&
                         recordHistItem.Version.Equals(lastHistoryRecordItem.Version, StringComparison.OrdinalIgnoreCase) &&
                         m_isLastRevisionAutoCorrectionEnabled));
                    changeGroup.Save();
                }

                Debug.Assert(perHistoryFieldLastIndex.ContainsKey(histFieldName), "perHistoryFieldLastIndex.ContainsKey(histFieldName) returns false");
                string deltaComputeProcessLookupId = CQDeltaComputationProgressLookupService.CreateHistoryItemId(recordEntDefName, recordDispName, histFieldName);
                DeltaComputeProgressService.UpdateCache(deltaComputeProcessLookupId, perHistoryFieldLastIndex[histFieldName]);
            }

            #endregion

            #region process attachment

            OAdAttachmentFields aAttachmentFields = CQWrapper.GetAttachmentFields(aRecord);

            for (int aAttachmentFieldsIndex = 0;
                 aAttachmentFieldsIndex < CQWrapper.AttachmentsFieldsCount(aAttachmentFields);
                 aAttachmentFieldsIndex++)
            {
                object             ob = (object)aAttachmentFieldsIndex;
                OAdAttachmentField aAttachmentField = CQWrapper.AttachmentsFieldsItem(aAttachmentFields, ref ob);
                string             fieldName        = CQWrapper.GetAttachmentFieldName(aAttachmentField);

                ChangeGroup changeGroup = m_changeGroupService.CreateChangeGroupForDeltaTable(
                    string.Format("{0}:{1}:{2}", recordDispName, "Attachments", fieldName));

                // process all attachments
                OAdAttachments attachments = CQWrapper.GetAttachments(aAttachmentField);
                for (int attachmentIndex = 0;
                     attachmentIndex < CQWrapper.AttachmentsCount(attachments);
                     attachmentIndex++)
                {
                    object        obIndex     = (object)attachmentIndex;
                    OAdAttachment aAttachment = CQWrapper.AttachmentsItem(attachments, ref obIndex);

                    ClearQuestAttachmentItem attachmentItem = new ClearQuestAttachmentItem(aRecord, aAttachmentField, aAttachment, UserSessionConnConfig);
                    attachmentItem.CQSession = m_userSession;
                    attachmentItem.CreateChangeAction(changeGroup, lastHistoryRecordItem.Version);
                }

                if (changeGroup.Actions.Count > 0)
                {
                    changeGroup.Save();
                }
            }

            #endregion
        }
        public bool Update(
            ClearQuestMigrationContext migrationContext,
            Session cqSession,
            OAdEntity hostRecord,
            LinkChangeAction linkChangeAction)
        {
            if (null == linkChangeAction)
            {
                throw new ArgumentNullException("linkChangeAction");
            }

            if (!linkChangeAction.Link.LinkType.ReferenceName.Equals(REFERENCE_NAME))
            {
                throw new ArgumentException("Link type mismatch.");
            }

            string childRecEntityDefName;

            if (!ClearQuestRecordArtifactHandler.TryExtractRecordDefName(linkChangeAction.Link.TargetArtifact,
                                                                         out childRecEntityDefName))
            {
                return(false);
            }
            string childRecDispName;

            if (!ClearQuestRecordArtifactHandler.TryExtractRecordDispName(linkChangeAction.Link.TargetArtifact,
                                                                          out childRecDispName))
            {
                return(false);
            }

            OAdEntity childEntity = CQWrapper.GetEntity(cqSession, childRecEntityDefName, childRecDispName);

            if (null == childEntity)
            {
                return(false);
            }

            // check if hostRecord already has a duplicate of this childRecord
            bool duplicateAlreadyExist = HasDuplicateRecord(hostRecord, childRecEntityDefName, childRecDispName);

            // find out the child entity's current state
            // find the current state
            string childEntityDefName = CQWrapper.GetEntityDefName(childEntity);

            OAdFieldInfo aFldInfo       = CQWrapper.GetEntityFieldValue(childEntity, migrationContext.GetStateField(childEntityDefName));
            string       srcState       = CQWrapper.GetFieldValue(aFldInfo);
            OAdEntityDef childEntityDef = CQWrapper.GetEntityDef(cqSession, childEntityDefName);

            if (linkChangeAction.ChangeActionId.Equals(WellKnownChangeActionId.Add))
            {
                if (duplicateAlreadyExist)
                {
                    // [teyang] TODO
                    return(false);
                }

                string[] changeActionNames = CQUtilityMethods.FindAllActionNameByTypeAndSourceState(
                    childEntityDef,
                    srcState,
                    CQConstants.ACTION_DUPLICATE);

                string changeActionName = string.Empty;
                if (changeActionNames.Length == 0)
                {
                    // [teyang] TODO conflict
                }
                else if (changeActionNames.Length > 1)
                {
                    // [teyang] TODO conflict
                }
                else
                {
                    changeActionName = changeActionNames[0];
                }

                if (!string.IsNullOrEmpty(changeActionName))
                {
                    CQWrapper.MarkEntityAsDuplicate(cqSession, childEntity, hostRecord, changeActionName);

                    string retVal = CQWrapper.Validate(childEntity);
                    if (string.IsNullOrEmpty(retVal))
                    {
                        // [teyang] TODO conflict
                    }

                    retVal = CQWrapper.Commmit(childEntity);
                    if (string.IsNullOrEmpty(retVal))
                    {
                        // [teyang] TODO conflict
                    }
                }
            }
            else if (linkChangeAction.ChangeActionId.Equals(WellKnownChangeActionId.Delete))
            {
                if (!duplicateAlreadyExist)
                {
                    // [teyang] TODO
                    return(false);
                }

                string[] changeActionNames = CQUtilityMethods.FindAllActionNameByTypeAndSourceState(
                    childEntityDef,
                    srcState,
                    CQConstants.ACTION_UNDUPLICATE);

                string changeActionName = string.Empty;
                if (changeActionNames.Length == 0)
                {
                    // [teyang] TODO conflict
                }
                else if (changeActionNames.Length > 1)
                {
                    // [teyang] TODO conflict
                }
                else
                {
                    changeActionName = changeActionNames[0];
                }

                if (!string.IsNullOrEmpty(changeActionName))
                {
                    CQWrapper.UnmarkEntityAsDuplicate(cqSession, childEntity, changeActionName);

                    string retVal = CQWrapper.Validate(childEntity);
                    if (string.IsNullOrEmpty(retVal))
                    {
                        // [teyang] TODO conflict
                    }

                    retVal = CQWrapper.Commmit(childEntity);
                    if (string.IsNullOrEmpty(retVal))
                    {
                        // [teyang] TODO conflict
                    }
                }
            }
            else
            {
                //throw new MigrationException(TfsWITAdapterResources.ErrorUnsupportedChangeAction);
            }

            return(true);
        }
        public XmlDocument CreateRecordDesc(
            OAdEntity record,
            string versionStr,
            ClearQuestMigrationContext migrationContext,
            bool isLastRevOfThisSyncCycle)
        {
            string   lastAuthor;
            DateTime lastChangeDate;

            FindLastRevDtls(record, out lastAuthor, out lastChangeDate);

            ClearQuestRecordDescription recordDesc = new ClearQuestRecordDescription();

            recordDesc.CreateHeader(lastAuthor, lastChangeDate, MigrationRecordId, EntityDefName, versionStr, isLastRevOfThisSyncCycle);

            object[] fieldNames = (object[])CQWrapper.GetEntityFieldNames(record);
            foreach (object fldName in fieldNames)
            {
                string fieldName = (string)fldName;
                if (s_skipAlgorithm.SkipField(fieldName))
                {
                    TraceManager.TraceInformation("Skipping Field '{0}' while migrating data for Entity '{1}'",
                                                  fieldName, EntityDefName);
                    continue;
                }

                OAdFieldInfo fldInfo     = CQWrapper.GetEntityFieldValue(record, fieldName);
                int          cqFieldType = CQWrapper.GetFieldType(fldInfo);

                switch (cqFieldType)
                {
                case CQConstants.FIELD_INT:
                case CQConstants.FIELD_ID:
                case CQConstants.FIELD_SHORT_STRING:
                case CQConstants.FIELD_STATE:
                case CQConstants.FIELD_DBID:
                case CQConstants.FIELD_STATETYPE:
                case CQConstants.FIELD_RECORDTYPE:
                {
                    string fldValue = CQWrapper.GetFieldValue(fldInfo);
                    recordDesc.AddField(fieldName, string.Empty, fldValue ?? String.Empty);
                }
                break;

                case CQConstants.FIELD_MULTILINE_STRING:
                {
                    string fldValue = CQWrapper.GetFieldValue(fldInfo);

                    if (migrationContext == null ||
                        !CQStringComparer.FieldName.Equals(migrationContext.NotesLogFieldName, fieldName))
                    {
                        // non-log field
                        try
                        {
                            var aTestEntity = CreateTestEntity(record, migrationContext);

                            object[] choices = (object[])CQWrapper.GetFieldChoiceList(aTestEntity, fieldName);
                            if (choices != null && choices.Length > 0)
                            {
                                // Multi Line String with List of Allowed/Suggested Values.. replace all '\n' with comma
                                // fix for bug# 429098
                                if (fldValue != null)
                                {
                                    fldValue = fldValue.Replace("\n", ",");
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            // NOTE:
                            // This feature of testing the multiline string choices create a dummy CQ record
                            // The API call CreateTestEntity requires WRITE permission to CQ
                            // If the migration account doesn't have the permission, we will simply use
                            // the field's current value
                            TraceManager.TraceInformation(
                                "Skipping retrieval of Allowed Values for field '{0}' - Write permission is needed. Error: {1}",
                                fieldName, ex.Message);
                        }

                        recordDesc.AddField(fieldName, string.Empty, fldValue);
                    }
                    else if (fldValue != null)
                    {
                        // log field

                        StringBuilder     sb    = new StringBuilder();
                        List <CQNotesLog> notes = CQNotesLog.Parse(fldValue);
                        foreach (CQNotesLog note in notes)
                        {
                            if (string.IsNullOrEmpty(note.Content) ||
                                note.Content.Contains(Constants.PlatformCommentSuffixMarker))
                            {
                                // skip empty logs or those generated by this adapter
                                continue;
                            }

                            if (note.Header.ChangeDate.CompareTo(migrationContext.CurrentHWMBaseLine) <= 0)
                            {
                                // skip the logs before the hwm
                                continue;
                            }

                            sb.AppendFormat("{0} {1} {2}\n",
                                            CQNotesLogHeader.NotesLogHeaderIdentifier,
                                            note.HeaderString,
                                            CQNotesLogHeader.NotesLogHeaderIdentifier);
                            sb.AppendLine(note.Content);
                        }

                        string extractedLog = sb.ToString();

                        if (!string.IsNullOrEmpty(extractedLog))
                        {
                            recordDesc.AddField(fieldName, string.Empty, extractedLog);
                        }
                    }
                }
                break;

                case CQConstants.FIELD_DATE_TIME:
                {
                    string fldValue = CQWrapper.GetFieldValue(fldInfo);
                    if (fldValue != null)
                    {
                        // the time returned from CQ API is the local time..
                        DateTime fldVal = DateTime.Parse(fldValue, CultureInfo.CurrentCulture);

                        //convert it in UTC
                        DateTime utcTime = UtilityMethods.ConvertLocalToUTC(fldVal);
                        TraceManager.TraceInformation("Field [{0}], CQ Time [{1}], UTC Time [{2}]",
                                                      fieldName, fldVal.ToString(), utcTime.ToString());

                        recordDesc.AddField(fieldName, string.Empty, utcTime.ToString());
                    }
                    else
                    {
                        recordDesc.AddField(fieldName, string.Empty, string.Empty);
                    }
                }
                break;

                case CQConstants.FIELD_REFERENCE:
                {
                    // get the current entity def handle
                    OAdEntityDef curEntityDef  = CQWrapper.GetEntityDef(CQSession, EntityDefName);
                    OAdEntityDef refEntityDef  = CQWrapper.GetFieldReferenceEntityDef(curEntityDef, fieldName);
                    string       refEntityName = CQWrapper.GetEntityDefName(refEntityDef);

                    if (CQWrapper.GetFieldValueStatus(fldInfo) == (int)CQConstants.FieldStatus.HAS_VALUE)
                    {
                        // single value required
                        string refFldVal = CQWrapper.GetFieldValue(fldInfo);
                        recordDesc.AddField(fieldName, string.Empty, refFldVal ?? string.Empty);
                    }
                    else
                    {
                        recordDesc.AddField(fieldName, string.Empty, string.Empty);
                    }
                }
                break;

                case CQConstants.FIELD_REFERENCE_LIST:
                {
                    // get the current entity def handle
                    OAdEntityDef curEntityDef  = CQWrapper.GetEntityDef(CQSession, EntityDefName);
                    OAdEntityDef refEntityDef  = CQWrapper.GetFieldReferenceEntityDef(curEntityDef, fieldName);
                    string       refEntityName = CQWrapper.GetEntityDefName(refEntityDef);

                    object[] refFldValues = CQWrapper.GetFieldValueAsList(fldInfo);
                    if (refFldValues != null)
                    {
                        StringBuilder userList = new StringBuilder();
                        for (int valueIndex = 0; valueIndex < refFldValues.Length; valueIndex++)
                        {
                            object refFldObj = refFldValues[valueIndex];
                            if (valueIndex > 0)
                            {
                                userList.Append(",");
                            }

                            userList.Append((string)refFldObj);
                        }
                        recordDesc.AddField(fieldName, string.Empty, userList.ToString());
                    }
                    else
                    {
                        recordDesc.AddField(fieldName, string.Empty, string.Empty);
                    }
                }
                break;

                case CQConstants.FIELD_ATTACHMENT_LIST:
                case CQConstants.FIELD_JOURNAL:
                    TraceManager.TraceInformation("Skipping the Field migration for Internal Field Type '{0}'",
                                                  cqFieldType);
                    // not migrating these fields as they are CQ internal fields
                    continue;

                default:
                    TraceManager.TraceInformation("Skipping the Field migration for Unkknown Field Type '{0}'",
                                                  cqFieldType);
                    break;
                } // end of switch cqFieldType
            }     // end of foreach fieldNames


            return(recordDesc.DescriptionDocument);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="action"></param>
        /// <param name="convRslt"></param>
        /// <param name="stateTransitFieldNode"></param>
        /// <param name="skipFields"></param>
        /// <returns></returns>
        private bool ChangeRecordState(
            OAdEntity entity,
            IMigrationAction action,
            ConversionResult convRslt,
            XmlNode stateTransitFieldNode,
            out List <string> processedFields)
        {
            processedFields = new List <string>();

            string destState = UtilityMethods.ExtractSingleFieldValue(stateTransitFieldNode);

            Debug.Assert(!string.IsNullOrEmpty(destState), "string.IsNullOrEmpty(newState)");

            // get the record's display name for updating conversion history
            string recordDisplayName = CQWrapper.GetEntityDisplayName(entity);

            string entityDefName = CQWrapper.GetEntityDefName(entity);

            // find the current state
            OAdFieldInfo aFldInfo = CQWrapper.GetEntityFieldValue(entity, m_migrationContext.GetStateField(entityDefName));
            string       srcState = CQWrapper.GetFieldValue(aFldInfo);

            if (CQStringComparer.StateName.Equals(srcState, destState))
            {
                // state does not change, skip this action
                return(false);
            }

            // find action def name
            OAdEntityDef entityDef = CQWrapper.GetEntityDef(m_userSession, entityDefName);

            string[] changeActionNames = CQUtilityMethods.FindAllActionNameByTypeAndStateTransition(entityDef, srcState, destState, CQConstants.ACTION_CHANGE);

            if (changeActionNames.Length == 0)
            {
                // [teyang] todo error handling
                throw new InvalidOperationException();
            }

            string changeActionName = changeActionNames[0];

            // *********
            // cache the current history count for all "history fields"
            // i.e. pairs of HistoryFieldName, count
            Dictionary <string, int> recordHistoryCountCache = new Dictionary <string, int>();

            BuildRecordHistoryCountCache(entity, recordHistoryCountCache);

            StringBuilder updateLog = new StringBuilder();

            PrintUpdateLogHeader(action, updateLog);

            // mark entity to be editable with the desired state-change action)
            CQWrapper.EditEntity(m_userSession, entity, changeActionName);

            XmlNodeList columns = action.MigrationActionDescription.SelectNodes("/WorkItemChanges/Columns/Column");

            if (null == columns)
            {
                throw new MigrationException(ClearQuestResource.ClearQuest_Error_InvalidActionDescription, action.ActionId);
            }

            foreach (XmlNode columnData in columns)
            {
                string stringVal = columnData.FirstChild.InnerText;
                string fieldName = columnData.Attributes["ReferenceName"].Value;

                Debug.Assert(!string.IsNullOrEmpty(fieldName),
                             "Field ReferenceName is absent in the Migration Description");


                OAdFieldInfo aFieldInfo        = CQWrapper.GetEntityFieldValue(entity, fieldName);
                int          fieldRequiredness = CQWrapper.GetRequiredness(aFieldInfo);
                if (fieldRequiredness != CQConstants.MANDATORY)
                {
                    // skipping all non-mandatory fields
                    continue;
                }

                int attempt1Count = 0;
                if (!SetFieldValue(action, entity, fieldName, stringVal, ref attempt1Count))
                {
                    return(false);
                }
                AddFieldToUpdateLog(fieldName, stringVal, updateLog);
                processedFields.Add(fieldName);
            }

            AddLineToUpdateLog(updateLog);
            int attempt2Count = 0;

            if (!SetFieldValue(action, entity, NoteEntryFieldName, updateLog.ToString(), ref attempt2Count))
            {
                return(false);
            }

            string retVal = CQWrapper.Validate(entity);

            if (!string.IsNullOrEmpty(retVal))
            {
                // [teyang] TODO conflict handling
                throw new InvalidOperationException(retVal);
            }

            retVal = CQWrapper.Commmit(entity);
            if (!string.IsNullOrEmpty(retVal))
            {
                // [teyang] TODO conflict handling
                throw new InvalidOperationException(retVal);
            }

            if (action.State == ActionState.Pending)
            {
                action.State = ActionState.Complete;
            }

            // *********
            // now comparing to the cache, so that we can clearly identify the item:version pairs
            // e.g. TargetCQRecordDisplayName : HistoryFieldName::LatestHistoryIndex
            Dictionary <string, int[]> updatedHistoryIndices = new Dictionary <string, int[]>();

            FindUpdatedHistoryIndices(entity, recordHistoryCountCache, updatedHistoryIndices);
            recordHistoryCountCache.Clear();

            foreach (string histFieldName in updatedHistoryIndices.Keys)
            {
                foreach (int histIndex in updatedHistoryIndices[histFieldName])
                {
                    UpdateConversionHistory(action,
                                            recordDisplayName,
                                            CQHistoryMigrationItem.CreateHistoryItemVersion(histFieldName, histIndex),
                                            convRslt);
                }
            }

            return(true);
        }
        private void AddAttachment(IMigrationAction action, ConversionResult convRslt)
        {
            string attName                = UtilityMethods.ExtractAttachmentName(action);
            string lengthStr              = UtilityMethods.ExtractAttachmentLength(action);
            string attComment             = UtilityMethods.ExtractAttachmentComment(action);
            string ownerRecordDisplayName = FindTargetWorkItemId(action);
            string ownerRecordType        = UtilityMethods.ExtractRecordType(action);

            string filePath = Path.Combine(m_configurationService.WorkspaceRoot,
                                           ownerRecordDisplayName + attName);

            try
            {
                // find the entity
                OAdEntity entity = CQWrapper.GetEntity(m_userSession, ownerRecordType, ownerRecordDisplayName);

                if (AttachmentExists(entity, attName, attComment, lengthStr))
                {
                    action.State = ActionState.Skipped;
                    return;
                }


                // find the change action def name
                string       entityDefName = CQWrapper.GetEntityDefName(entity);
                OAdEntityDef entityDef     = CQWrapper.GetEntityDef(m_userSession, entityDefName);

                string modifyActionDefName = FindCQActionDefName(entityDef, CQConstants.ACTION_MODIFY);

                // mark entity to be editable
                CQWrapper.EditEntity(m_userSession, entity, modifyActionDefName);

                // cache the current history count for all "history fields"
                // i.e. pairs of HistoryFieldName, count
                Dictionary <string, int> recordHistoryCountCache = new Dictionary <string, int>();
                BuildRecordHistoryCountCache(entity, recordHistoryCountCache);

                action.SourceItem.Download(filePath);

                string attachmentField = m_migrationContext.GetAttachmentSinkField(entityDefName);
                string retVal          = CQWrapper.AddAttachmentFieldValue(entity, attachmentField, attName, filePath);
                if (!string.IsNullOrEmpty(retVal))
                {
                    // teyang_todo attachment conflict
                }

                retVal = CQWrapper.Validate(entity);
                if (!string.IsNullOrEmpty(retVal))
                {
                    // [teyang] TODO conflict management
                    throw new InvalidOperationException();
                }

                retVal = CQWrapper.Commmit(entity);
                if (!string.IsNullOrEmpty(retVal))
                {
                    // [teyang] TODO conflict management
                    throw new InvalidOperationException();
                }

                if (action.State == ActionState.Pending)
                {
                    action.State = ActionState.Complete;
                }

                // *********
                // now comparing to the cache, so that we can clearly identify the item:version pairs
                // e.g. TargetCQRecordDisplayName : HistoryFieldName::LatestHistoryIndex
                Dictionary <string, int[]> updatedHistoryIndices = new Dictionary <string, int[]>();
                FindUpdatedHistoryIndices(entity, recordHistoryCountCache, updatedHistoryIndices);
                recordHistoryCountCache.Clear();

                foreach (string histFieldName in updatedHistoryIndices.Keys)
                {
                    foreach (int histIndex in updatedHistoryIndices[histFieldName])
                    {
                        UpdateConversionHistory(action,
                                                ownerRecordDisplayName,
                                                CQHistoryMigrationItem.CreateHistoryItemVersion(histFieldName, histIndex),
                                                convRslt);
                    }
                }
            }
            finally
            {
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                }
            }
        }
        public void ExtractLinkChangeActions(
            Session session,
            OAdEntity hostRecord,
            List <LinkChangeGroup> linkChangeGroups)
        {
            string hostRecDispName      = CQWrapper.GetEntityDisplayName(hostRecord);
            string hostRecEntityDefName = CQWrapper.GetEntityDefName(hostRecord);

            if (string.IsNullOrEmpty(hostRecEntityDefName) ||
                !CQStringComparer.EntityName.Equals(hostRecEntityDefName, this.m_hostRecordType))
            {
                return;
            }

            string hostRecMigrItemId = UtilityMethods.CreateCQRecordMigrationItemId(hostRecEntityDefName, hostRecDispName);

            var linkChangeGroup = new LinkChangeGroup(hostRecMigrItemId, LinkChangeGroup.LinkChangeGroupStatus.Created, false);

            OAdFieldInfo fldInfo     = CQWrapper.GetEntityFieldValue(hostRecord, m_referenceFieldName);
            int          cqFieldType = CQWrapper.GetFieldType(fldInfo);

            if (cqFieldType == CQConstants.FIELD_REFERENCE)
            {
                // get the current entity def handle
                OAdEntityDef curEntityDef          = CQWrapper.GetEntityDef(session, hostRecEntityDefName);
                OAdEntityDef refEntityDef          = CQWrapper.GetFieldReferenceEntityDef(curEntityDef, m_referenceFieldName);
                string       childRecEntityDefName = CQWrapper.GetEntityDefName(refEntityDef);

                int valueStatus = CQWrapper.GetFieldValueStatus(fldInfo);
                if (valueStatus == (int)CQConstants.FieldStatus.HAS_VALUE)
                {
                    // single value required
                    string refFldVal = CQWrapper.GetFieldValue(fldInfo);
                    if (!CQStringComparer.RecordName.Equals(refFldVal, hostRecDispName))
                    {
                        // NOT a reference to self.. Note TFS cannot have a reference to self
                        OAdEntity childRecord = CQWrapper.GetEntity(session, childRecEntityDefName, refFldVal);
                        if (null != childRecord)
                        {
                            string childRecDispName   = CQWrapper.GetEntityDisplayName(childRecord);
                            string childRecMigrItemId = UtilityMethods.CreateCQRecordMigrationItemId(
                                childRecEntityDefName, childRecDispName);

                            ILink refFieldLink = new ArtifactLink(
                                hostRecDispName,
                                new Artifact(hostRecMigrItemId, new ClearQuestRecordArtifactType()),
                                new Artifact(childRecMigrItemId, new ClearQuestRecordArtifactType()),
                                string.Empty,
                                this);

                            LinkChangeAction action = new LinkChangeAction(
                                WellKnownChangeActionId.Add,
                                refFieldLink,
                                LinkChangeAction.LinkChangeActionStatus.Created,
                                false);

                            linkChangeGroup.AddChangeAction(action);
                        }
                        else
                        {
                            // [teyang] TODO replace debug assertion with a conflict?
                            Debug.Assert(false, "null == childRecord");
                        }
                    }
                }
            }

            linkChangeGroups.Add(linkChangeGroup);
        }
        public bool Update(
            ClearQuestMigrationContext migrationContext,
            Session session,
            OAdEntity hostRecord,
            LinkChangeAction linkChangeAction)
        {
            if (null == linkChangeAction)
            {
                throw new ArgumentNullException("linkChangeAction");
            }

            if (!linkChangeAction.Link.LinkType.ReferenceName.StartsWith(ReferenceNameQualifier))
            {
                throw new ArgumentException("Link type mismatch.");
            }

            string childRecEntityDefName;

            if (!ClearQuestRecordArtifactHandler.TryExtractRecordDefName(linkChangeAction.Link.TargetArtifact,
                                                                         out childRecEntityDefName))
            {
                return(false);
            }
            string childRecDispName;

            if (!ClearQuestRecordArtifactHandler.TryExtractRecordDispName(linkChangeAction.Link.TargetArtifact,
                                                                          out childRecDispName))
            {
                return(false);
            }

            string hostRecEntityDefName = CQWrapper.GetEntityDefName(hostRecord);

            if (string.IsNullOrEmpty(hostRecEntityDefName) ||
                !CQStringComparer.EntityName.Equals(hostRecEntityDefName, this.m_hostRecordType))
            {
                return(false);
            }

            string refFieldName = linkChangeAction.Link.LinkType.ReferenceName.Substring(ReferenceNameQualifier.Length);

            if (string.IsNullOrEmpty(refFieldName))
            {
                return(false);
            }

            // retrieve reference field information
            OAdFieldInfo refFieldInfo = CQWrapper.GetEntityFieldValue(hostRecord, refFieldName);
            int          cqFieldType  = CQWrapper.GetFieldType(refFieldInfo);

            if (cqFieldType != CQConstants.FIELD_REFERENCE)
            {
                // the field is not of the reference type

                // [teyang] TODO conflict?
                return(false);
            }

            // get the current entity def
            OAdEntityDef hostRecordEntityDef      = CQWrapper.GetEntityDef(session, CQWrapper.GetEntityDefName(hostRecord));
            OAdEntityDef childRecordEntityDef     = CQWrapper.GetFieldReferenceEntityDef(hostRecordEntityDef, refFieldName);
            string       childRecordEntityDefName = CQWrapper.GetEntityDefName(childRecordEntityDef);

            if (!CQStringComparer.EntityName.Equals(childRecordEntityDefName, childRecEntityDefName))
            {
                // the field is not designated to hold reference to the EntityType of the target artifact

                // [teyang] TODO conflict?
                return(false);
            }

            int valueStatus = CQWrapper.GetFieldValueStatus(refFieldInfo);

            if (valueStatus == (int)CQConstants.FieldStatus.HAS_VALUE)
            {
                // the field already has a reference value set

                // single value required
                string refFldVal = CQWrapper.GetFieldValue(refFieldInfo);
                if (CQStringComparer.RecordName.Equals(refFldVal, childRecDispName))
                {
                    // the target artifact is already referenced in the field

                    // [teyang] TODO conflict?
                    return(false);
                }
                else
                {
                    // field currently holds a reference to another entity

                    // [teyang] TODO conflict?
                    return(false);
                }
            }

            string[] modifyActionNames = CQUtilityMethods.FindAllChangeActionNamesByType(
                session, hostRecord, CQConstants.ACTION_MODIFY);

            if (modifyActionNames.Length == 0)
            {
                // [teyang] TODO conflict?
                return(false);
            }
            else if (modifyActionNames.Length > 1)
            {
                // [teyang] TODO conflict?
                return(false);
            }
            else
            {
                string modAction = modifyActionNames[0];

                CQWrapper.EditEntity(session, hostRecord, modAction);

                string retVal = CQWrapper.SetFieldValue(hostRecord, refFieldName, childRecDispName);

                retVal = CQWrapper.Validate(hostRecord);
                if (string.IsNullOrEmpty(retVal))
                {
                    // [teyang] TODO conflict
                    return(false);
                }

                retVal = CQWrapper.Commmit(hostRecord);
                if (string.IsNullOrEmpty(retVal))
                {
                    // [teyang] TODO conflict
                    return(false);
                }

                return(true);
            }
        }