private void VerifyReplace(IDomainObjectDTORepository dtoRepos, string guid, bool expectReplace, int numOfPubs)
		{
			var dto = dtoRepos.GetDTO(guid);
			var xElt = XElement.Parse(dto.Xml);
			Assert.That(xElt.Attribute("class").Value == "LexEntry", "Giud not representing a LexEntry after migration to 7000041.");
			var hasDoNotShow = xElt.Element("DoNotShowMainEntryIn");
			string expect = "";
			if (!expectReplace)
				expect = "not ";
			Assert.That(expectReplace == (hasDoNotShow != null),
				"LexEntry " + guid + " did " + expect + "expect ExcludeAsHeadword to be replaced by DoNotShowMainEntryIn, but it didn't happen in migration to 7000041.");
			if (expectReplace)
			{ // Check that each publication is referenced
				var noShows = SurrogatesIn(xElt, "DoNotShowMainEntryIn", numOfPubs);
				var dtoPubist = dtoRepos.GetDTO(CmPossibilityListTags.kguidPublicationsList.ToString());
				Assert.That(dtoPubist != null, "This project has no Publications list after migration 7000041");
				var xPubist = XElement.Parse(dtoPubist.Xml);
				var cfElements = SurrogatesIn(xPubist, "Possibilities", numOfPubs);
				foreach (var xObj in cfElements)
				{	// there must be 1 to 1 map of objsur's in hasDoNotShow and xPubist
					string pubGuid = xObj.Attribute("guid").Value;
					int n = 0;
					foreach (var yObj in noShows)
					{
						if (pubGuid == yObj.Attribute("guid").Value)
						{
							Assert.That(yObj.Attribute("t").Value == "r", "7000041 Migrated test XML pub list items are not references");
							break;
						}
					}
				}
			}
		}
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Looks for CmFile objects included in LangProject. If found, will look for CmFile in
		/// correct location and replace reference on CmPicture with that new CmFile.
		/// </summary>
		/// <param name="repoDto">
		/// Repository of all CmObject DTOs available for one migration step.
		/// </param>
		/// <remarks>
		/// Implementors of this interface should ensure the Repository's
		/// starting model version number is correct for the step.
		/// Implementors must also increment the Repository's model version number
		/// at the end of its migration work.
		///
		/// The method also should normally modify the xml string(s)
		/// of relevant DTOs, since that string will be used by the main
		/// data migration calling client (ie. BEP).
		/// </remarks>
		/// ------------------------------------------------------------------------------------
		public void PerformMigration(IDomainObjectDTORepository repoDto)
		{
			DataMigrationServices.CheckVersionNumber(repoDto, 7000033);
			var langProj = repoDto.AllInstancesSansSubclasses("LangProject").First();
			var langProjElement = XElement.Parse(langProj.Xml);
			var pictures = langProjElement.Element("Pictures");

			if (pictures != null && pictures.Elements().Count() > 1)
			{
				DomainObjectDTO folder = null;
				bool foundFiles = false;
				foreach (var x in pictures.Elements())
				{
					var xObj = repoDto.GetDTO(x.Attribute("guid").Value);
					if (xObj.Classname == "CmFolder")
					{
						// empty folders can just be removed
						var xObjElement = XElement.Parse(xObj.Xml);
						if (xObjElement.Element("Files") == null)
							DataMigrationServices.RemoveIncludingOwnedObjects(repoDto, xObj, true);
						else if (folder == null)
							folder = xObj;
						else
							MoveFileReferences(repoDto, langProj, xObj, folder);
					}
					else
						foundFiles = true;
				}

				if (folder != null && foundFiles)
					RemoveInvalidFiles(repoDto, langProj, folder);

			}
			DataMigrationServices.IncrementVersionNumber(repoDto);
		}
        private void RemoveInvalidFiles(IDomainObjectDTORepository repoDto,
                                        DomainObjectDTO langProj, DomainObjectDTO folder)
        {
            var langProjElement = XElement.Parse(langProj.Xml);
            var pictures        = langProjElement.Element("Pictures");
            var fileMap         = CreateFilePathToGuidMap(repoDto, folder);
            var pictureMap      = CreateFileGuidToPictureMap(repoDto);

            foreach (var x in pictures.Elements())
            {
                var xObj = repoDto.GetDTO(x.Attribute("guid").Value);
                if (xObj.Classname == "CmFile")
                {
                    string replacementFileGuid;
                    string filePath = GetFilePath(xObj);
                    if (filePath != null &&
                        fileMap.TryGetValue(filePath.ToLowerInvariant(), out replacementFileGuid))
                    {
                        UpdatePictureReferences(repoDto, xObj, replacementFileGuid, pictureMap);
                        DataMigrationServices.RemoveIncludingOwnedObjects(repoDto, xObj, true);
                    }
                    else if (!pictureMap.ContainsKey(xObj.Guid))
                    {
                        DataMigrationServices.RemoveIncludingOwnedObjects(repoDto, xObj, true);
                    }
                    else
                    {
                        MoveFileToFolder(repoDto, folder, xObj);
                        RemoveReferenceFromPictures(repoDto, langProj, xObj.Guid);
                    }
                }
            }
        }
Exemple #4
0
        /// <summary>
        /// Given that the element has been changed to represent the desired new state of some DTO,
        /// save the change. This overload finds the DTO from the guid attribute on the element.
        /// </summary>
        private void UpdateDto(IDomainObjectDTORepository domainObjectDtoRepository, XElement element)
        {
            DomainObjectDTO dto = domainObjectDtoRepository.GetDTO(element.Attribute("guid").Value);

            dto.Xml = element.ToString();
            domainObjectDtoRepository.Update(dto);
        }
Exemple #5
0
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Change model for Data Notebook to combine the RnEvent and RnAnalysis classes
        /// into RnGenericRec
        /// </summary>
        /// <param name="domainObjectDtoRepository">
        /// Repository of all CmObject DTOs available for one migration step.
        /// </param>
        /// <remarks>
        /// The method must add/remove/update the DTOs to the repository,
        /// as it adds/removes objects as part of its work.
        ///
        /// Implementors of this interface should ensure the Repository's
        /// starting model version number is correct for the step.
        /// Implementors must also increment the Repository's model version number
        /// at the end of its migration work.
        ///
        /// The method also should normally modify the xml string(s)
        /// of relevant DTOs, since that string will be used by the main
        /// data migration calling client (ie. BEP).
        /// </remarks>
        /// ------------------------------------------------------------------------------------
        public void PerformMigration(IDomainObjectDTORepository domainObjectDtoRepository)
        {
            DataMigrationServices.CheckVersionNumber(domainObjectDtoRepository, 7000004);

            // 1. Change EventTypes field to RecTypes
            var nbkDto            = domainObjectDtoRepository.AllInstancesSansSubclasses("RnResearchNbk").First();
            var nbkElement        = XElement.Parse(nbkDto.Xml);
            var nbkClsElement     = nbkElement.Element("RnResearchNbk");
            var typesFieldElement = nbkClsElement.Element("EventTypes");
            var typesSurElement   = typesFieldElement.Element("objsur");

            nbkClsElement.Add(new XElement("RecTypes", typesSurElement));
            typesFieldElement.Remove();
            DataMigrationServices.UpdateDTO(domainObjectDtoRepository, nbkDto, nbkElement.ToString());

            // 2. Add Analysis possibility to Record Types list
            var typesGuid    = typesSurElement.Attribute("guid").Value;
            var typesDto     = domainObjectDtoRepository.GetDTO(typesGuid);
            var typesElement = XElement.Parse(typesDto.Xml);

            typesElement.XPathSelectElement("CmMajorObject/Name/AUni[@ws='en']").SetValue("Entry Types");
            var posElement = typesElement.XPathSelectElement("CmPossibilityList/Possibilities");

            posElement.Add(
                DataMigrationServices.CreateOwningObjSurElement("82290763-1633-4998-8317-0EC3F5027FBD"));
            DataMigrationServices.UpdateDTO(domainObjectDtoRepository, typesDto,
                                            typesElement.ToString());
            var ord = posElement.Elements().Count();

            var nowStr      = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
            var typeElement = new XElement("rt", new XAttribute("class", "CmPossibility"),
                                           new XAttribute("guid", "82290763-1633-4998-8317-0EC3F5027FBD"),
                                           new XAttribute("ownerguid", typesGuid),
                                           new XAttribute("owningflid", "8008"), new XAttribute("owningord", ord.ToString()),
                                           new XElement("CmObject"),
                                           new XElement("CmPossibility",
                                                        new XElement("Abbreviation",
                                                                     new XElement("AUni", new XAttribute("ws", "en"), "Ana")),
                                                        new XElement("BackColor", new XAttribute("val", "16711680")),
                                                        new XElement("DateCreated", new XAttribute("val", nowStr)),
                                                        new XElement("DateModified", new XAttribute("val", nowStr)),
                                                        new XElement("Description",
                                                                     new XElement("AStr", new XAttribute("ws", "en"),
                                                                                  new XElement("Run", new XAttribute("ws", "en"), "Reflection on events and other types of data, such as literature summaries or interviews. An analysis does not add data; it interprets and organizes data. An analysis entry may synthesize emerging themes. It may draw connections between observations. It is a place to speculate and hypothesize, or document moments of discovery and awareness. Analytic notes can be turned into articles. Or, they may just be steps on the stairway toward greater understanding."))),
                                                        new XElement("ForeColor", new XAttribute("val", "16777215")),
                                                        new XElement("Name",
                                                                     new XElement("AUni", new XAttribute("ws", "en"), "Analysis")),
                                                        new XElement("UnderColor", new XAttribute("val", "255")),
                                                        new XElement("UnderStyle", new XAttribute("val", "1"))));

            domainObjectDtoRepository.Add(new DomainObjectDTO("82290763-1633-4998-8317-0EC3F5027FBD",
                                                              "CmPossibility", typeElement.ToString()));

            // 3. Move the attributes that are in RnEvent and RnAnalysis into RnGenericRec.
            MigrateSubclassOfGenRec(domainObjectDtoRepository, "RnEvent");
            MigrateSubclassOfGenRec(domainObjectDtoRepository, "RnAnalysis");

            DataMigrationServices.IncrementVersionNumber(domainObjectDtoRepository);
        }
		private XElement[] VerifyEntryRef(IDomainObjectDTORepository dtoRepos, string guid, int cfCount, int showComplexFormsInCount)
		{
			var dto = dtoRepos.GetDTO(guid);
			var xElt = XElement.Parse(dto.Xml);
			SurrogatesIn(xElt, "ComponentLexemes", cfCount);
			SurrogatesIn(xElt, "PrimaryLexemes", showComplexFormsInCount);
			var cfElements = SurrogatesIn(xElt, "ShowComplexFormsIn", showComplexFormsInCount);
			return cfElements.ToArray();
		}
        private static XElement GetPossibilityListNameElement(IDomainObjectDTORepository dtoRepos,
                                                              XElement ownerElement, string flidName)
        {
            Assert.IsNotNull(ownerElement.XPathSelectElement(flidName));
            var xPath = flidName + "/objsur";
            var dto   = dtoRepos.GetDTO(ownerElement.XPathSelectElement(xPath).Attribute("guid").Value);

            return(XElement.Parse(dto.Xml).XPathSelectElement("Name"));
        }
		/// <summary>
		/// Updates the Data Notebook RecordTypes possibilities to use specific GUIDs.
		/// </summary>
		/// <param name="domainObjectDtoRepository">Repository of all CmObject DTOs available for one migration step.</param>
		public void PerformMigration(IDomainObjectDTORepository domainObjectDtoRepository)
		{
			DataMigrationServices.CheckVersionNumber(domainObjectDtoRepository, 7000010);

			DomainObjectDTO nbkDto = domainObjectDtoRepository.AllInstancesSansSubclasses("RnResearchNbk").First();
			XElement nbkElem = XElement.Parse(nbkDto.Xml);
			var recTypesGuid = (string) nbkElem.XPathSelectElement("RnResearchNbk/RecTypes/objsur").Attribute("guid");
			var stack = new Stack<DomainObjectDTO>(domainObjectDtoRepository.GetDirectlyOwnedDTOs(recTypesGuid));
			IEnumerable<DomainObjectDTO> recDtos = domainObjectDtoRepository.AllInstancesSansSubclasses("RnGenericRec");
			IEnumerable<DomainObjectDTO> overlayDtos = domainObjectDtoRepository.AllInstancesSansSubclasses("CmOverlay");
			while (stack.Count > 0)
			{
				DomainObjectDTO dto = stack.Pop();
				foreach (DomainObjectDTO childDto in domainObjectDtoRepository.GetDirectlyOwnedDTOs(dto.Guid))
					stack.Push(childDto);
				XElement posElem = XElement.Parse(dto.Xml);
				XElement uniElem = posElem.XPathSelectElement("CmPossibility/Abbreviation/AUni[@ws='en']");
				if (uniElem != null)
				{
					string newGuid = null;
					switch (uniElem.Value)
					{
						case "Con":
							newGuid = "B7B37B86-EA5E-11DE-80E9-0013722F8DEC";
							break;
						case "Intv":
							newGuid = "B7BF673E-EA5E-11DE-9C4D-0013722F8DEC";
							break;
						case "Str":
							newGuid = "B7C8F092-EA5E-11DE-8D7D-0013722F8DEC";
							break;
						case "Uns":
							newGuid = "B7D4DC4A-EA5E-11DE-867C-0013722F8DEC";
							break;
						case "Lit":
							newGuid = "B7E0C7F8-EA5E-11DE-82CC-0013722F8DEC";
							break;
						case "Obs":
							newGuid = "B7EA5156-EA5E-11DE-9F9C-0013722F8DEC";
							break;
						case "Per":
							newGuid = "B7F63D0E-EA5E-11DE-9F02-0013722F8DEC";
							break;
						case "Ana":
							newGuid = "82290763-1633-4998-8317-0EC3F5027FBD";
							break;
					}
					if (newGuid != null)
						DataMigrationServices.ChangeGuid(domainObjectDtoRepository, dto, newGuid, recDtos.Concat(overlayDtos));
				}
			}

			DomainObjectDTO recTypesDto = domainObjectDtoRepository.GetDTO(recTypesGuid);
			DataMigrationServices.ChangeGuid(domainObjectDtoRepository, recTypesDto, "D9D55B12-EA5E-11DE-95EF-0013722F8DEC", overlayDtos);
			DataMigrationServices.IncrementVersionNumber(domainObjectDtoRepository);
		}
        private static void CheckMainObject(IDomainObjectDTORepository dtoRepos, string guid, IEnumerable <KeyValuePair <string, string> > propertiesToCheck)
        {
            var dto       = dtoRepos.GetDTO(guid);
            var rtElement = XElement.Parse(dto.Xml);

            foreach (var kvp in propertiesToCheck)
            {
                CheckProperty(rtElement, kvp);
            }
        }
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Change model for Data Notebook to combine the RnEvent and RnAnalysis classes
		/// into RnGenericRec
		/// </summary>
		/// <param name="domainObjectDtoRepository">
		/// Repository of all CmObject DTOs available for one migration step.
		/// </param>
		/// <remarks>
		/// The method must add/remove/update the DTOs to the repository,
		/// as it adds/removes objects as part of its work.
		///
		/// Implementors of this interface should ensure the Repository's
		/// starting model version number is correct for the step.
		/// Implementors must also increment the Repository's model version number
		/// at the end of its migration work.
		///
		/// The method also should normally modify the xml string(s)
		/// of relevant DTOs, since that string will be used by the main
		/// data migration calling client (ie. BEP).
		/// </remarks>
		/// ------------------------------------------------------------------------------------
		public void PerformMigration(IDomainObjectDTORepository domainObjectDtoRepository)
		{
			DataMigrationServices.CheckVersionNumber(domainObjectDtoRepository, 7000004);

			// 1. Change EventTypes field to RecTypes
			var nbkDto = domainObjectDtoRepository.AllInstancesSansSubclasses("RnResearchNbk").First();
			var nbkElement = XElement.Parse(nbkDto.Xml);
			var nbkClsElement = nbkElement.Element("RnResearchNbk");
			var typesFieldElement = nbkClsElement.Element("EventTypes");
			var typesSurElement = typesFieldElement.Element("objsur");
			nbkClsElement.Add(new XElement("RecTypes", typesSurElement));
			typesFieldElement.Remove();
			DataMigrationServices.UpdateDTO(domainObjectDtoRepository, nbkDto, nbkElement.ToString());

			// 2. Add Analysis possibility to Record Types list
			var typesGuid = typesSurElement.Attribute("guid").Value;
			var typesDto = domainObjectDtoRepository.GetDTO(typesGuid);
			var typesElement = XElement.Parse(typesDto.Xml);
			typesElement.XPathSelectElement("CmMajorObject/Name/AUni[@ws='en']").SetValue("Entry Types");
			var posElement = typesElement.XPathSelectElement("CmPossibilityList/Possibilities");
			posElement.Add(
				DataMigrationServices.CreateOwningObjSurElement("82290763-1633-4998-8317-0EC3F5027FBD"));
			DataMigrationServices.UpdateDTO(domainObjectDtoRepository, typesDto,
				typesElement.ToString());
			var ord = posElement.Elements().Count();

			var nowStr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
			var typeElement = new XElement("rt", new XAttribute("class", "CmPossibility"),
				new XAttribute("guid", "82290763-1633-4998-8317-0EC3F5027FBD"),
				new XAttribute("ownerguid", typesGuid),
				new XAttribute("owningflid", "8008"), new XAttribute("owningord", ord.ToString()),
				new XElement("CmObject"),
				new XElement("CmPossibility",
					new XElement("Abbreviation",
						new XElement("AUni", new XAttribute("ws", "en"), "Ana")),
					new XElement("BackColor", new XAttribute("val", "16711680")),
					new XElement("DateCreated", new XAttribute("val", nowStr)),
					new XElement("DateModified", new XAttribute("val", nowStr)),
					new XElement("Description",
						new XElement("AStr", new XAttribute("ws", "en"),
							new XElement("Run", new XAttribute("ws", "en"), "Reflection on events and other types of data, such as literature summaries or interviews. An analysis does not add data; it interprets and organizes data. An analysis entry may synthesize emerging themes. It may draw connections between observations. It is a place to speculate and hypothesize, or document moments of discovery and awareness. Analytic notes can be turned into articles. Or, they may just be steps on the stairway toward greater understanding."))),
					new XElement("ForeColor", new XAttribute("val", "16777215")),
					new XElement("Name",
						new XElement("AUni", new XAttribute("ws", "en"), "Analysis")),
					new XElement("UnderColor", new XAttribute("val", "255")),
					new XElement("UnderStyle", new XAttribute("val", "1"))));
			domainObjectDtoRepository.Add(new DomainObjectDTO("82290763-1633-4998-8317-0EC3F5027FBD",
				"CmPossibility", typeElement.ToString()));

			// 3. Move the attributes that are in RnEvent and RnAnalysis into RnGenericRec.
			MigrateSubclassOfGenRec(domainObjectDtoRepository, "RnEvent");
			MigrateSubclassOfGenRec(domainObjectDtoRepository, "RnAnalysis");

			DataMigrationServices.IncrementVersionNumber(domainObjectDtoRepository);
		}
Exemple #11
0
        private XElement[] VerifyEntryRef(IDomainObjectDTORepository dtoRepos, string guid, int cfCount, int showComplexFormsInCount)
        {
            var dto  = dtoRepos.GetDTO(guid);
            var xElt = XElement.Parse(dto.Xml);

            SurrogatesIn(xElt, "ComponentLexemes", cfCount);
            SurrogatesIn(xElt, "PrimaryLexemes", showComplexFormsInCount);
            var cfElements = SurrogatesIn(xElt, "ShowComplexFormsIn", showComplexFormsInCount);

            return(cfElements.ToArray());
        }
Exemple #12
0
 private static DomainObjectDTO GetDTOIfItExists(IDomainObjectDTORepository dtoRepository, string sGuid)
 {
     try
     {
         return(dtoRepository.GetDTO(sGuid));
     }
     catch (ArgumentException)
     {
         return(null);
     }
 }
Exemple #13
0
        private bool IsWeatherUsed(IDomainObjectDTORepository repoDTO, List <DomainObjectDTO> collectOverlaysToRemove)
        {
            DomainObjectDTO dtoLP        = GetDtoLangProj(repoDTO);
            string          sLpXml       = dtoLP.Xml;
            int             idxW         = sLpXml.IndexOf("<WeatherConditions>");
            var             sguidWeather = ExtractFirstGuid(sLpXml, idxW, " guid=\"");
            DomainObjectDTO dtoWeather   = repoDTO.GetDTO(sguidWeather);
            var             weatherItems = new HashSet <string>();

            CollectItems(repoDTO, dtoWeather, weatherItems);
            foreach (var dto in repoDTO.AllInstancesWithSubclasses("RnGenericRec"))
            {
                string sXml = dto.Xml;
                int    idx  = sXml.IndexOf("<Weather>");
                if (idx > 0)
                {
                    int idxEnd = sXml.IndexOf("</Weather>");
                    if (idxEnd > idx)
                    {
                        string s = sXml.Substring(idx, idxEnd - idx);
                        if (s.Contains("<objsur "))
                        {
                            return(true);
                        }
                    }
                }
                bool dummy = false;
                if (StringContainsRefToItemInList("PhraseTags", weatherItems, sXml, ref dummy))
                {
                    return(true);
                }
            }
            foreach (var dto in repoDTO.AllInstancesSansSubclasses("CmOverlay"))
            {
                string sXml           = dto.Xml;
                bool   hasOtherItems  = false;
                bool   hasWeatherRef  = StringContainsRefToItemInList("PossItems", weatherItems, sXml, ref hasOtherItems);
                var    weatherListSet = new HashSet <string>();
                weatherListSet.Add(sguidWeather.ToLowerInvariant());
                hasWeatherRef |= StringContainsRefToItemInList("PossList", weatherListSet, sXml, ref hasOtherItems);
                if (hasWeatherRef)
                {
                    if (hasOtherItems)
                    {
                        return(true);                        // an overlay with a mixture of weather and non-weather items is a problem
                    }
                    // One with only weather refs (and not used, since we know nothing is tagged to weather)
                    // will be deleted.
                    collectOverlaysToRemove.Add(dto);
                }
            }
            return(false);
        }
Exemple #14
0
        public void PerformMigration(IDomainObjectDTORepository domainObjectDtoRepository)
        {
            DataMigrationServices.CheckVersionNumber(domainObjectDtoRepository, 7000051);

            var          newGuidValue = Guid.NewGuid().ToString().ToLowerInvariant();
            const string className    = "WfiMorphBundle";
            var          wmbList      = domainObjectDtoRepository.AllInstancesSansSubclasses(className);

            foreach (var wmb in wmbList)
            {
                XElement wmbElt   = XElement.Parse(wmb.Xml);
                var      morphElt = wmbElt.Element("Morph");
                // if we don't have a morph reference,
                // then there's nothing to copy into the form field.
                if (morphElt == null)
                {
                    continue;
                }
                var objsurElt      = morphElt.Element("objsur");
                var dtoMorphTarget = domainObjectDtoRepository.GetDTO(objsurElt.Attribute("guid").Value);
                // for each form alternative, copy the writing system

                // if for some reason there is a morphbundle form that already exists, delete it before inserting another.
                var formElt = wmbElt.Element("Form");
                if (formElt != null)
                {
                    formElt.Remove();
                }

                var morphTargetElt     = XElement.Parse(dtoMorphTarget.Xml);
                var morphTargetFormElt = morphTargetElt.Element("Form");
                if (morphTargetFormElt == null)
                {
                    continue;
                }
                formElt = XElement.Parse("<Form/>");
                wmbElt.AddFirst(formElt);
                foreach (var aUniElt in morphTargetFormElt.Elements("AUni"))
                {
                    string ws            = aUniElt.Attribute("ws").Value;
                    string form          = aUniElt.Value;
                    var    newFormAltElt = XElement.Parse(String.Format("<AStr ws=\"{0}\"/>", ws));
                    formElt.Add(newFormAltElt);
                    var newRunElt = XElement.Parse(String.Format("<Run ws=\"{0}\">{1}</Run>", ws, XmlUtils.MakeSafeXml(form)));
                    newFormAltElt.Add(newRunElt);
                }
                DataMigrationServices.UpdateDTO(domainObjectDtoRepository, wmb, wmbElt.ToString());
            }

            DataMigrationServices.IncrementVersionNumber(domainObjectDtoRepository);
        }
        private void VerifyReplace(IDomainObjectDTORepository dtoRepos, string guid, bool expectReplace, int numOfPubs)
        {
            var dto  = dtoRepos.GetDTO(guid);
            var xElt = XElement.Parse(dto.Xml);

            Assert.That(xElt.Attribute("class").Value == "LexEntry", "Giud not representing a LexEntry after migration to 7000041.");
            var    hasDoNotShow = xElt.Element("DoNotShowMainEntryIn");
            string expect       = "";

            if (!expectReplace)
            {
                expect = "not ";
            }
            Assert.That(expectReplace == (hasDoNotShow != null),
                        "LexEntry " + guid + " did " + expect + "expect ExcludeAsHeadword to be replaced by DoNotShowMainEntryIn, but it didn't happen in migration to 7000041.");
            if (expectReplace)
            {             // Check that each publication is referenced
                var noShows   = SurrogatesIn(xElt, "DoNotShowMainEntryIn", numOfPubs);
                var dtoPubist = dtoRepos.GetDTO(CmPossibilityListTags.kguidPublicationsList.ToString());
                Assert.That(dtoPubist != null, "This project has no Publications list after migration 7000041");
                var xPubist    = XElement.Parse(dtoPubist.Xml);
                var cfElements = SurrogatesIn(xPubist, "Possibilities", numOfPubs);
                foreach (var xObj in cfElements)
                {                       // there must be 1 to 1 map of objsur's in hasDoNotShow and xPubist
                    string pubGuid = xObj.Attribute("guid").Value;
                    int    n       = 0;
                    foreach (var yObj in noShows)
                    {
                        if (pubGuid == yObj.Attribute("guid").Value)
                        {
                            Assert.That(yObj.Attribute("t").Value == "r", "7000041 Migrated test XML pub list items are not references");
                            break;
                        }
                    }
                }
            }
        }
        private Dictionary <string, string> CreateFilePathToGuidMap(IDomainObjectDTORepository repoDto, DomainObjectDTO folder)
        {
            var folderElement = XElement.Parse(folder.Xml);
            var map           = new Dictionary <string, string>();

            foreach (var file in folderElement.Element("Files").Elements())
            {
                var    fileGuid = file.Attribute("guid").Value;
                string filePath = GetFilePath(repoDto.GetDTO(fileGuid));
                if (filePath != null)
                {
                    map[filePath.ToLowerInvariant()] = fileGuid;
                }
            }
            return(map);
        }
Exemple #17
0
        private static void RemoveDanglingReferences(
            IDomainObjectDTORepository dtoRepos,
            IEnumerable <DomainObjectDTO> allDtos)
        {
            foreach (var currentDto in allDtos)
            {
                // Fetch the referred (regular reference or owning reference) to object guids.
                var referredToGuids = ExtractReferencedObjects(currentDto);

                // See if it is a dangling ref, where target object has been deleted.
                foreach (var targetGuid in referredToGuids)
                {
                    DomainObjectDTO referencedDto;
                    if (dtoRepos.TryGetValue(targetGuid, out referencedDto))
                    {
                        continue;
                    }

                    // targetGuid is a dangling reference.
                    // Remove the <objsur> element from referring object (kvp Key).
                    // The <objsur> will have its 'guid' attribute set to 'targetGuid'.
                    // This will work for owned as well as standard referenced objects.
                    var targetGuidAsString = targetGuid.ToLower();
                    var referringDto       = dtoRepos.GetDTO(currentDto.Guid);
                    var referringElement   = XElement.Parse(referringDto.Xml);
                    var emptyPropElements  = new List <XElement>();
                    foreach (var danglingRef in (referringElement.Descendants("objsur").Where(
                                                     objSurrElement => objSurrElement.Attribute("guid").Value.ToLower() == targetGuidAsString)).ToList())
                    {
                        var propElement = danglingRef.Parent;
                        danglingRef.Remove();
                        if (!propElement.HasAttributes && !propElement.HasElements)
                        {
                            emptyPropElements.Add(propElement);
                        }
                    }
                    foreach (var emptyPropElement in emptyPropElements)
                    {
                        emptyPropElement.Remove();                         // Remove now empty property element.
                    }
                    // Reset the xml.
                    referringDto.Xml = referringElement.ToString();
                    dtoRepos.Update(referringDto);
                }
            }
        }
Exemple #18
0
        /// <summary>
        /// Add the reference collection of Senses to each reversal index
        /// and fill it with the Senses that referenced the ReversalIndexEntry
        /// </summary>
        public void AddSensesToReversalIndexEntry(IDomainObjectDTORepository repoDto)
        {
            // Get all the LexSense Classes
            var allLexSenses = repoDto.AllInstancesWithSubclasses("LexSense");

            foreach (var aLexSense in allLexSenses)
            {
                var lexSenseElement = XElement.Parse(aLexSense.Xml);
                // Get the ReversalEntries within the LexSense
                var reversalEntries = lexSenseElement.Element("ReversalEntries");
                if (reversalEntries == null)
                {
                    continue;
                }

                // Get the Current LexSense's Guid
                var lexSenseGuid = lexSenseElement.Attribute("guid")?.Value;
                Debug.Assert(lexSenseGuid != null, "lexSenseGuid != null");

                // Loop through the ReversalEntries within the LexSense
                var reversalEntriesList = reversalEntries.Elements("objsur");
                foreach (var aReversalEntry in reversalEntriesList)
                {
                    // Get the Current ReversalEntries (objsur) Guid from the objsur
                    var reversalEntryGuid = aReversalEntry.Attribute("guid")?.Value;

                    // Get the Reversal Entry Object, that has the specified Guid, that needs to be modified
                    var aReversalIndexEntry = repoDto.GetDTO(reversalEntryGuid);

                    // Add Senses to the Reversal Entry
                    var reversalIndexElement = XElement.Parse(aReversalIndexEntry.Xml);
                    var sensesElement        = reversalIndexElement.Element("Senses");
                    if (sensesElement == null)
                    {
                        sensesElement = new XElement("Senses");
                        reversalIndexElement.Add(sensesElement);
                    }
                    var objsur = new XElement("objsur", new XAttribute("guid", lexSenseGuid), new XAttribute("t", "r"));
                    sensesElement.Add(objsur);

                    // Update the Reversal Entry
                    DataMigrationServices.UpdateDTO(repoDto, aReversalIndexEntry, reversalIndexElement.ToString());
                }
            }
        }
		public void PerformMigration(IDomainObjectDTORepository domainObjectDtoRepository)
		{
			DataMigrationServices.CheckVersionNumber(domainObjectDtoRepository, 7000051);

			var newGuidValue = Guid.NewGuid().ToString().ToLowerInvariant();
			const string className = "WfiMorphBundle";
			var wmbList = domainObjectDtoRepository.AllInstancesSansSubclasses(className);
			foreach (var wmb in wmbList)
			{
				XElement wmbElt = XElement.Parse(wmb.Xml);
				var morphElt = wmbElt.Element("Morph");
				// if we don't have a morph reference,
				// then there's nothing to copy into the form field.
				if (morphElt == null)
					continue;
				var objsurElt = morphElt.Element("objsur");
				var dtoMorphTarget = domainObjectDtoRepository.GetDTO(objsurElt.Attribute("guid").Value);
				// for each form alternative, copy the writing system

				// if for some reason there is a morphbundle form that already exists, delete it before inserting another.
				var formElt = wmbElt.Element("Form");
				if (formElt != null)
					formElt.Remove();

				var morphTargetElt = XElement.Parse(dtoMorphTarget.Xml);
				var morphTargetFormElt = morphTargetElt.Element("Form");
				if (morphTargetFormElt == null)
					continue;
				formElt = XElement.Parse("<Form/>");
				wmbElt.AddFirst(formElt);
				foreach (var aUniElt in morphTargetFormElt.Elements("AUni"))
				{
					string ws = aUniElt.Attribute("ws").Value;
					string form = aUniElt.Value;
					var newFormAltElt = XElement.Parse(String.Format("<AStr ws=\"{0}\"/>", ws));
					formElt.Add(newFormAltElt);
					var newRunElt = XElement.Parse(String.Format("<Run ws=\"{0}\">{1}</Run>", ws, XmlUtils.MakeSafeXml(form)));
					newFormAltElt.Add(newRunElt);
				}
				DataMigrationServices.UpdateDTO(domainObjectDtoRepository, wmb, wmbElt.ToString());
			}

			DataMigrationServices.IncrementVersionNumber(domainObjectDtoRepository);
		}
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Looks for CmFile objects included in LangProject. If found, will look for CmFile in
        /// correct location and replace reference on CmPicture with that new CmFile.
        /// </summary>
        /// <param name="repoDto">
        /// Repository of all CmObject DTOs available for one migration step.
        /// </param>
        /// <remarks>
        /// Implementors of this interface should ensure the Repository's
        /// starting model version number is correct for the step.
        /// Implementors must also increment the Repository's model version number
        /// at the end of its migration work.
        ///
        /// The method also should normally modify the xml string(s)
        /// of relevant DTOs, since that string will be used by the main
        /// data migration calling client (ie. BEP).
        /// </remarks>
        /// ------------------------------------------------------------------------------------
        public void PerformMigration(IDomainObjectDTORepository repoDto)
        {
            DataMigrationServices.CheckVersionNumber(repoDto, 7000033);
            var langProj        = repoDto.AllInstancesSansSubclasses("LangProject").First();
            var langProjElement = XElement.Parse(langProj.Xml);
            var pictures        = langProjElement.Element("Pictures");

            if (pictures != null && pictures.Elements().Count() > 1)
            {
                DomainObjectDTO folder     = null;
                bool            foundFiles = false;
                foreach (var x in pictures.Elements())
                {
                    var xObj = repoDto.GetDTO(x.Attribute("guid").Value);
                    if (xObj.Classname == "CmFolder")
                    {
                        // empty folders can just be removed
                        var xObjElement = XElement.Parse(xObj.Xml);
                        if (xObjElement.Element("Files") == null)
                        {
                            DataMigrationServices.RemoveIncludingOwnedObjects(repoDto, xObj, true);
                        }
                        else if (folder == null)
                        {
                            folder = xObj;
                        }
                        else
                        {
                            MoveFileReferences(repoDto, langProj, xObj, folder);
                        }
                    }
                    else
                    {
                        foundFiles = true;
                    }
                }

                if (folder != null && foundFiles)
                {
                    RemoveInvalidFiles(repoDto, langProj, folder);
                }
            }
            DataMigrationServices.IncrementVersionNumber(repoDto);
        }
Exemple #21
0
        private void VerifyAgentEvaluation(XElement approves, IDomainObjectDTORepository dtoRepos, out string guid)
        {
            Assert.IsNotNull(approves);
            var objsur = approves.Element("objsur");

            Assert.IsNotNull(objsur);
            Assert.AreEqual("o", objsur.Attribute("t").Value);
            guid = objsur.Attribute("guid").Value;

            var eval = dtoRepos.GetDTO(guid);

            Assert.AreEqual("CmAgentEvaluation", eval.Classname);
            var evalElt = XElement.Parse(eval.Xml);

            Assert.IsNotNull(evalElt.Elements("CmObject").First());
            var agentEval = evalElt.Elements("CmAgentEvaluation").First();

            Assert.IsNotNull(agentEval);
            Assert.AreEqual(0, agentEval.Elements().Count());
        }
        private void MoveFileReferences(IDomainObjectDTORepository repoDto, DomainObjectDTO langProj,
                                        DomainObjectDTO srcFolder, DomainObjectDTO destFolder)
        {
            var srcFolderElement  = XElement.Parse(srcFolder.Xml);
            var destFolderElement = XElement.Parse(destFolder.Xml);
            var destFileRefs      = destFolderElement.Element("Files");

            foreach (var fileRef in srcFolderElement.Element("Files").Elements())
            {
                destFileRefs.Add(fileRef);
                var guid        = fileRef.Attribute("guid").Value;
                var file        = repoDto.GetDTO(guid);
                var fileElement = XElement.Parse(file.Xml);
                fileElement.Attribute("ownerguid").SetValue(destFolder.Guid);
                DataMigrationServices.UpdateDTO(repoDto, file, fileElement.ToString());
            }

            RemoveReferenceFromPictures(repoDto, langProj, srcFolder.Guid);
            repoDto.Remove(srcFolder);
            DataMigrationServices.UpdateDTO(repoDto, destFolder, destFolderElement.ToString());
        }
		private void MoveFileReferences(IDomainObjectDTORepository repoDto, DomainObjectDTO langProj,
			DomainObjectDTO srcFolder, DomainObjectDTO destFolder)
		{
			var srcFolderElement = XElement.Parse(srcFolder.Xml);
			var destFolderElement = XElement.Parse(destFolder.Xml);
			var destFileRefs = destFolderElement.Element("Files");
			foreach (var fileRef in srcFolderElement.Element("Files").Elements())
			{
				destFileRefs.Add(fileRef);
				var guid = fileRef.Attribute("guid").Value;
				var file = repoDto.GetDTO(guid);
				var fileElement = XElement.Parse(file.Xml);
				fileElement.Attribute("ownerguid").SetValue(destFolder.Guid);
				DataMigrationServices.UpdateDTO(repoDto, file, fileElement.ToString());
			}

			RemoveReferenceFromPictures(repoDto, langProj, srcFolder.Guid);
			repoDto.Remove(srcFolder);
			DataMigrationServices.UpdateDTO(repoDto, destFolder, destFolderElement.ToString());
		}
		private static DomainObjectDTO CheckPara(IDomainObjectDTORepository dtoRepos, string paraGuid,
			int segmentCount, bool checkForParseIsCurrent, bool expectedParseIsCurrentValue,
			out List<XElement> newSegmentObjSurElements)
		{
			var currentParaDto = dtoRepos.GetDTO(paraGuid);
			var newParaElement = XElement.Parse(currentParaDto.Xml);
			var stTxtParaInnerElement = newParaElement.Element("StTxtPara");
			var segmentsElement = stTxtParaInnerElement.Element("Segments");
			if (segmentCount == 0)
			{
				newSegmentObjSurElements = null;
				Assert.IsNull(segmentsElement, "Existing Segments element.");
			}
			else
			{
				Assert.IsNotNull(segmentsElement, "Missing Segments element.");
				// Check that it has correct number of new segments.
				newSegmentObjSurElements = segmentsElement.Elements("objsur").ToList();
				Assert.IsNotNull(newSegmentObjSurElements, "Missing objsur elements.");
				Assert.AreEqual(segmentCount, newSegmentObjSurElements.Count(), "Wrong number of new segments.");
			}

			if (checkForParseIsCurrent)
			{
				Assert.AreEqual(expectedParseIsCurrentValue,
					bool.Parse(stTxtParaInnerElement.Element("ParseIsCurrent").Attribute("val").Value),
					"Wrong value for ParseIsCurrent.");
			}

			return currentParaDto;
		}
		private void VerifyAgentEvaluation(XElement approves, IDomainObjectDTORepository dtoRepos, out string guid)
		{
			Assert.IsNotNull(approves);
			var objsur = approves.Element("objsur");
			Assert.IsNotNull(objsur);
			Assert.AreEqual("o",objsur.Attribute("t").Value);
			guid = objsur.Attribute("guid").Value;

			var eval = dtoRepos.GetDTO(guid);
			Assert.AreEqual("CmAgentEvaluation", eval.Classname);
			var evalElt = XElement.Parse(eval.Xml);

			Assert.IsNotNull(evalElt.Elements("CmObject").First());
			var agentEval = evalElt.Elements("CmAgentEvaluation").First();
			Assert.IsNotNull(agentEval);
			Assert.AreEqual(0, agentEval.Elements().Count());
		}
Exemple #26
0
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Changes the use of CmAgentEvaluation, so that instead of one evaluation per agent/target pair
        /// owned by Agent.Evauations and referring to the target, there are only two CmAgentEvaluations
        /// owned by each CmAgent in their Approves and Disapproves properties, and they are referred to
        /// by the new WfiAnalysis.Evaluations Reference Collection.
        ///
        /// Specifically, for each CmAgent,
        /// - Create two CmAgentEvaluations, one owned in Approves and one in Disapproves.
        /// - For each item in Evaluations, if Accepted, add the appropriate Approves evaluation to
        ///     the target of the evaluation, otherwise, add the appropriate Disapproves (if there is a target).
        /// - Delete the Evaluations.
        ///
        /// As a side effect, since all existing CmAgentEvaluations are deleted, obsolete properties are removed.
        /// </summary>
        /// <param name="domainObjectDtoRepository">Repository of all CmObject DTOs available for
        /// one migration step.</param>
        /// ------------------------------------------------------------------------------------
        public void PerformMigration(IDomainObjectDTORepository domainObjectDtoRepository)
        {
            DataMigrationServices.CheckVersionNumber(domainObjectDtoRepository, 7000013);

            // from guid of a WfiAnalysis to list of evaluations.
            var map = new Dictionary <string, List <string> >();

            foreach (var agentDto in domainObjectDtoRepository.AllInstancesSansSubclasses("CmAgent"))
            {
                var rtElement    = XElement.Parse(agentDto.Xml);
                var agentElement = rtElement.Elements("CmAgent").First();
                // Create two new CmAgentEvaluations.
                var newApprovesEval    = MakeEvaluation(agentDto.Guid, domainObjectDtoRepository, agentElement, "Approves");
                var newDisapprovesEval = MakeEvaluation(agentDto.Guid, domainObjectDtoRepository, agentElement, "Disapproves");
                var evaluations        = agentElement.Elements("Evaluations").FirstOrDefault();
                if (evaluations != null)
                {
                    foreach (var objsur in evaluations.Elements("objsur"))
                    {
                        var evalGuidAttr = objsur.Attribute("guid");
                        if (evalGuidAttr == null)
                        {
                            continue;
                        }

                        var evalGuid        = evalGuidAttr.Value;
                        var obsoleteEvalDto = domainObjectDtoRepository.GetDTO(evalGuid);
                        if (obsoleteEvalDto == null)
                        {
                            continue;                             // defensive (RandyR says there is no need to be defensive, since the repos will throw an exception, if the guid ois not found.)
                        }
                        var agentEvalElt = XElement.Parse(obsoleteEvalDto.Xml).Element("CmAgentEvaluation");
                        if (agentEvalElt == null)
                        {
                            continue;                             // paranoid! (Also, no need for paranoia, since the element *must* be present, or the object cannot be reconstituted.)
                        }
                        // Delete/Remove the old evaluation.
                        domainObjectDtoRepository.Remove(obsoleteEvalDto);

                        var  acceptedElt = agentEvalElt.Element("Accepted");
                        bool accepted    = false;
                        if (acceptedElt != null)
                        {
                            var attr = acceptedElt.Attribute("val");
                            if (attr != null)
                            {
                                accepted = attr.Value.ToLowerInvariant() == "true";
                            }
                        }

                        var targetElt = agentEvalElt.Element("Target");
                        if (targetElt == null)
                        {
                            continue;
                        }
                        var targetObjsur = targetElt.Element("objsur");
                        if (targetObjsur == null)
                        {
                            continue;                             // paranoid
                        }
                        var targetGuidAttr = targetObjsur.Attribute("guid");
                        if (targetGuidAttr == null)
                        {
                            continue;                             // paranoid
                        }
                        var           targetGuid = targetGuidAttr.Value;
                        List <String> evals;
                        if (!map.TryGetValue(targetGuid, out evals))
                        {
                            evals           = new List <string>();
                            map[targetGuid] = evals;
                        }

                        evals.Add(accepted ? newApprovesEval.Guid : newDisapprovesEval.Guid);
                    }
                    evaluations.Remove();
                }
                agentDto.Xml = rtElement.ToString();
                domainObjectDtoRepository.Update(agentDto);
            }
            foreach (var kvp in map)
            {
                var analysisDto   = domainObjectDtoRepository.GetDTO(kvp.Key);
                var analysisRtElt = XElement.Parse(analysisDto.Xml);
                var analysisElt   = analysisRtElt.Element("WfiAnalysis");
                if (analysisElt == null)
                {
                    continue;                     // Paranoid
                }
                var evals = new XElement("Evaluations");
                analysisElt.Add(evals);
                foreach (var eval in kvp.Value)
                {
                    evals.Add(new XElement("objsur", new XAttribute("t", "r"), new XAttribute("guid", eval)));
                }
                analysisDto.Xml = analysisRtElt.ToString();
                domainObjectDtoRepository.Update(analysisDto);
            }

            DataMigrationServices.IncrementVersionNumber(domainObjectDtoRepository);
        }
Exemple #27
0
        /// <summary>
        /// Add a few items to the Notebook Record Type list, and rearrange the list a bit.  The original
        /// list should look something like:
        ///		Conversation
        ///		Interview
        ///			Structured
        ///			Unstructured
        ///		Literature Summary
        ///		Observation
        ///			Performance
        ///		Analysis
        ///	After the migration, the list should look something like:
        ///		Event
        ///			Observation
        ///			Conversation
        ///			Interview
        ///				Structured
        ///				Unstructured
        ///			Performance
        ///		Literature Summary
        ///		Analysis
        ///		Methodology
        ///		Weather
        /// </summary>
        /// <remarks>
        /// This implements FWR-643.  Note that users can edit this list, so any of the expected
        /// items could have been deleted or moved around in the list.  :-(
        /// </remarks>
        public void PerformMigration(IDomainObjectDTORepository repoDTO)
        {
            DataMigrationServices.CheckVersionNumber(repoDTO, 7000015);

            DomainObjectDTO dtoList             = repoDTO.GetDTO(ksguidRecTypesList);
            XElement        xeList              = XElement.Parse(dtoList.Xml);
            XElement        xeListPossibilities = xeList.XPathSelectElement("Possibilities");

            if (xeListPossibilities == null)
            {
                xeListPossibilities = new XElement("Possibilities");
                xeList.Add(xeListPossibilities);
            }
            // The user can edit the list, so these might possibly have been deleted (or moved).  :-(
            DomainObjectDTO dtoObservation  = GetDTOIfItExists(repoDTO, ksguidObservation);
            DomainObjectDTO dtoConversation = GetDTOIfItExists(repoDTO, ksguidConversation);
            DomainObjectDTO dtoInterview    = GetDTOIfItExists(repoDTO, ksguidInterview);
            DomainObjectDTO dtoPerformance  = GetDTOIfItExists(repoDTO, ksguidPerformance);

            // Create the new Event, Methodology, and Weather record types.
            var nowStr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");

            StringBuilder sb = new StringBuilder();

            sb.AppendFormat("<rt class=\"CmPossibility\" guid=\"{0}\" ownerguid=\"{1}\">",
                            ksguidEvent, ksguidRecTypesList);
            sb.Append("<Abbreviation><AUni ws=\"en\">Evnt</AUni></Abbreviation>");
            sb.Append("<Name><AUni ws=\"en\">Event</AUni></Name>");
            sb.AppendFormat("<DateCreated val=\"{0}\"/>", nowStr);
            sb.AppendFormat("<DateModified val=\"{0}\"/>", nowStr);
            sb.Append("</rt>");
            XElement xeEvent  = XElement.Parse(sb.ToString());
            var      dtoEvent = new DomainObjectDTO(ksguidEvent, "CmPossibility", xeEvent.ToString());

            repoDTO.Add(dtoEvent);
            xeListPossibilities.AddFirst(DataMigrationServices.CreateOwningObjSurElement(ksguidEvent));

            sb = new StringBuilder();
            sb.AppendFormat("<rt class=\"CmPossibility\" guid=\"{0}\" ownerguid=\"{1}\">",
                            ksguidMethodology, ksguidRecTypesList);
            sb.Append("<Abbreviation><AUni ws=\"en\">Method</AUni></Abbreviation>");
            sb.Append("<Name><AUni ws=\"en\">Methodology</AUni></Name>");
            sb.AppendFormat("<DateCreated val=\"{0}\"/>", nowStr);
            sb.AppendFormat("<DateModified val=\"{0}\"/>", nowStr);
            sb.Append("</rt>");
            var dtoMethod = new DomainObjectDTO(ksguidMethodology, "CmPossibility", sb.ToString());

            repoDTO.Add(dtoMethod);
            xeListPossibilities.LastNode.AddAfterSelf(DataMigrationServices.CreateOwningObjSurElement(ksguidMethodology));

            sb = new StringBuilder();
            sb.AppendFormat("<rt class=\"CmPossibility\" guid=\"{0}\" ownerguid=\"{1}\">",
                            ksguidWeather, ksguidRecTypesList);
            sb.Append("<Abbreviation><AUni ws=\"en\">Wthr</AUni></Abbreviation>");
            sb.Append("<Name><AUni ws=\"en\">Weather</AUni></Name>");
            sb.AppendFormat("<DateCreated val=\"{0}\"/>", nowStr);
            sb.AppendFormat("<DateModified val=\"{0}\"/>", nowStr);
            sb.Append("</rt>");
            var dtoWeather = new DomainObjectDTO(ksguidWeather, "CmPossibility", sb.ToString());

            repoDTO.Add(dtoWeather);
            xeListPossibilities.LastNode.AddAfterSelf(DataMigrationServices.CreateOwningObjSurElement(ksguidWeather));

            DataMigrationServices.UpdateDTO(repoDTO, dtoList, xeList.ToString());

            // Change the ownership links for the moved items.
            if (dtoObservation != null)
            {
                ChangeOwner(repoDTO, dtoObservation, ksguidEvent, "SubPossibilities");
            }
            if (dtoConversation != null)
            {
                ChangeOwner(repoDTO, dtoConversation, ksguidEvent, "SubPossibilities");
            }
            if (dtoInterview != null)
            {
                ChangeOwner(repoDTO, dtoInterview, ksguidEvent, "SubPossibilities");
            }
            if (dtoPerformance != null)
            {
                ChangeOwner(repoDTO, dtoPerformance, ksguidEvent, "SubPossibilities");
            }

            DataMigrationServices.IncrementVersionNumber(repoDTO);
        }
		/// <summary>
		/// Given that the element has been changed to represent the desired new state of some DTO,
		/// save the change. This overload finds the DTO from the guid attribute on the element.
		/// </summary>
		private void UpdateDto(IDomainObjectDTORepository domainObjectDtoRepository, XElement element)
		{
			DomainObjectDTO dto = domainObjectDtoRepository.GetDTO(element.Attribute("guid").Value);
			dto.Xml = element.ToString();
			domainObjectDtoRepository.Update(dto);
		}
		private Dictionary<string, string> CreateFilePathToGuidMap(IDomainObjectDTORepository repoDto, DomainObjectDTO folder)
		{
			var folderElement = XElement.Parse(folder.Xml);
			var map = new Dictionary<string, string>();
			foreach (var file in folderElement.Element("Files").Elements())
			{
				var fileGuid = file.Attribute("guid").Value;
				string filePath = GetFilePath(repoDto.GetDTO(fileGuid));
				if (filePath != null)
					map[filePath.ToLowerInvariant()] = fileGuid;
			}
			return map;
		}
		private static void CheckXfics(IDomainObjectDTORepository dtoRepos,
			XContainer newSegmentInnerElement, int expectedAnalysesCount,
			IList<string> analysesGuids)
		{
			var analysesElement = newSegmentInnerElement.Element("Analyses");
			if (expectedAnalysesCount == 0)
			{
				if (analysesElement != null)
					Assert.AreEqual(expectedAnalysesCount, analysesElement.Elements("objsur").Count(), "Unexpected analyses.");
				return; // nothing else to check (and it's OK if the element is null
			}
			Assert.IsNotNull(analysesElement, "Missing Analyses Element in the new Segment object.");
			var analObjSurElements = analysesElement.Elements("objsur");
			Assert.AreEqual(expectedAnalysesCount, analObjSurElements.Count(), "Wrong Analyses count.");
			for (var i = 0; i < expectedAnalysesCount; ++i)
			{
				var newAnalObjsurElement = analObjSurElements.ElementAt(i);
				Assert.IsNotNull(newAnalObjsurElement, "Missing objsur Element in the new Analyses element.");
				Assert.AreEqual("r", newAnalObjsurElement.Attribute("t").Value, "Not a reference property.");
				var analysisDto = dtoRepos.GetDTO(newAnalObjsurElement.Attribute("guid").Value);
				Assert.IsNotNull(analysisDto, "Missing analysis dto.");

				// Make sure the right analysis guid is used.
				Assert.AreEqual(analysesGuids[i].ToLower(), analysisDto.Guid.ToLower(), "Wrong guid.");
			}
		}
		public void PerformMigration(IDomainObjectDTORepository domainObjectDtoRepository)
		{
			DataMigrationServices.CheckVersionNumber(domainObjectDtoRepository, 7000064);

			var revIndexList = domainObjectDtoRepository.AllInstancesSansSubclasses("ReversalIndex");
			foreach (var revIndexDto in revIndexList)
			{
				var dirty = false;
				// grab ws name(s) from each Reversal Index
				var wsCodeNameDict = new Dictionary<string, string>();
				GetWsNamesFromReversalIndex(revIndexDto, wsCodeNameDict);

				// Find PartsOfSpeech possibility list
				string possListGuid;
				if (!GetGuidForPosListSafely(revIndexDto, out possListGuid))
					continue; // Can't find the PartsOfSpeech list without a guid!
				var posListDto = domainObjectDtoRepository.GetDTO(possListGuid);
				var listElt = XElement.Parse(posListDto.Xml);

				// Check for the right Depth, ItemClsid and IsSorted values
				var depthElt = listElt.Element(DepthProp);
				if (depthElt != null)
					depthElt.Remove(); // Don't want the old one, it was wrong!
				// Replace with a new Property
				var sbDepth = new StringBuilder();
				sbDepth.Append(OpenCloseTagWithValAttr(DepthProp, "127"));
				depthElt = XElement.Parse(sbDepth.ToString());
				listElt.Add(depthElt);
				var clsIdElt = listElt.Element(ClsProp);
				if (clsIdElt == null) // Don't replace an existing value
				{
					// Create the new property
					var sb = new StringBuilder();
					sb.Append(OpenCloseTagWithValAttr(ClsProp, Convert.ToString(PosClsId)));
					clsIdElt = XElement.Parse(sb.ToString());
					listElt.Add(clsIdElt);
					dirty = true;
				}
				var sortedElt = listElt.Element(SortProp);
				if (sortedElt == null)
				{
					var sb = new StringBuilder();
					sb.Append(OpenCloseTagWithValAttr(SortProp, Truth));
					sortedElt = XElement.Parse(sb.ToString());
					listElt.Add(sortedElt);
					dirty = true;
				}
				if (sortedElt.Attribute("val").Value != Truth)
				{
					sortedElt.SetAttributeValue("val", Truth);
					dirty = true;
				}

				// If Name exists skip it, otherwise put a valid name in for each ws that RI Name had.
				var nameElt = listElt.Element(Name);
				if (nameElt == null || nameElt.Element(Auni) == null)
				{
					if (nameElt != null)
						nameElt.Remove(); // Just in case we end up with an empty name element
					var sb = new StringBuilder();
					sb.Append(OpenTag(Name));
					foreach (var kvp in wsCodeNameDict)
					{
						var wsCode = kvp.Key;
						var wsName = kvp.Value;
						sb.AppendFormat(OpenTagWithWsAttr(Auni, wsCode));
						sb.AppendFormat(Strings.ksReversalIndexPOSListName, wsName);
						sb.Append(EndTag(Auni));
					}
					sb.Append(EndTag(Name));
					nameElt = XElement.Parse(sb.ToString());
					listElt.Add(nameElt);
					dirty = true;
				}
				if (dirty)
					DataMigrationServices.UpdateDTO(domainObjectDtoRepository, posListDto, listElt.ToString());
			}

			DataMigrationServices.IncrementVersionNumber(domainObjectDtoRepository);
		}
Exemple #32
0
 private IEnumerable <XElement> GetPossibilitiesInList(IDomainObjectDTORepository domainObjectDtoRepository, XElement langPossListElement)
 {
     return(from elt in langPossListElement.XPathSelectElements("Possibilities/objsur")
            select XElement.Parse(
                domainObjectDtoRepository.GetDTO(elt.Attribute("guid").Value).Xml));
 }
		private static void CheckMainObject(IDomainObjectDTORepository dtoRepos, string guid, IEnumerable<KeyValuePair<string, string>> propertiesToCheck)
		{
			var dto = dtoRepos.GetDTO(guid);
			var rtElement = XElement.Parse(dto.Xml);
			foreach (var kvp in propertiesToCheck)
				CheckProperty(rtElement, kvp);
		}
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Combine Sense and Sense Status lists into the Sense list.
		/// </summary>
		/// <param name="domainObjectDtoRepository">
		/// Repository of all CmObject DTOs available for one migration step.
		/// </param>
		/// <remarks>
		/// The method must add/remove/update the DTOs to the repository,
		/// as it adds/removes objects as part of its work.
		///
		/// Implementors of this interface should ensure the Repository's
		/// starting model version number is correct for the step.
		/// Implementors must also increment the Repository's model version number
		/// at the end of its migration work.
		///
		/// The method also should normally modify the xml string(s)
		/// of relevant DTOs, since that string will be used by the main
		/// data migration calling client (ie. BEP).
		/// </remarks>
		/// ------------------------------------------------------------------------------------
		public void PerformMigration(IDomainObjectDTORepository domainObjectDtoRepository)
		{
			DataMigrationServices.CheckVersionNumber(domainObjectDtoRepository, 7000023);

			// 1. Change the owning property from LangProject_AnalysisStatus to LangProject_Status

			string statusConfirmedGuid = "";
			IEnumerable<XElement> langPossList = null;
			var langProjDto = domainObjectDtoRepository.AllInstancesSansSubclasses("LangProject").First();
			var langProjElement = XElement.Parse(langProjDto.Xml);
			var statusElement = langProjElement.Element("AnalysisStatus");
			if (statusElement != null)
				statusElement.Name= "Status";
			UpdateDto(domainObjectDtoRepository,langProjDto,langProjElement);

			var langPossListGuid = GetGuidOfObjSurChild(statusElement);

			var langPossListDto = domainObjectDtoRepository.GetDTO(langPossListGuid);
			var langPossListElement = XElement.Parse(langPossListDto.Xml);

			var langPossListPossibilities = langPossListElement.Element("Possibilities");
			if (langPossListPossibilities == null)
			{
				langPossListElement.Add(XElement.Parse("<Possibilities></Possibilities>"));
				UpdateDto(domainObjectDtoRepository,langPossListDto,langPossListElement);
				// Put the 'Confirmed' status into the list.
				statusConfirmedGuid = MakeStatus(domainObjectDtoRepository, langPossListGuid, langPossListElement,
					"Confirmed", "Conf");
				langPossList = GetPossibilitiesInList(domainObjectDtoRepository, langPossListElement);
				UpdateDto(domainObjectDtoRepository,langPossListDto,langPossListElement);
			}
			else
			{
				// Get the actual elements that represent the possibility items in the AnalysisStatus possibility list.
				langPossList = GetPossibilitiesInList(domainObjectDtoRepository, langPossListElement);

				// 1a.  Verify the 'Confirmed' status exists in the list.
				statusConfirmedGuid = IsStatusInList(langPossList, "Confirmed");
				if (statusConfirmedGuid == null) //if not, add it
				{
					statusConfirmedGuid = MakeStatus(domainObjectDtoRepository, langPossListGuid, langPossListElement,
						"Confirmed", "Conf");
				}
				UpdateDto(domainObjectDtoRepository,langPossListDto,langPossListElement);
			}

			// 1b.  If any rnGeneric records point to the 'Approved' status, point them to 'Confirnmed'.
			var approvedGuid = IsStatusInList(langPossList, "Approved");
			if (approvedGuid != null)
				ReassignStatuses(domainObjectDtoRepository, approvedGuid, statusConfirmedGuid);

			// 2. Get the pointers to the Lexdb Status list (sense status)
			var lexDbElement = langProjElement.Element("LexDb");
			if (lexDbElement != null)
			{
				var lexDto = domainObjectDtoRepository.AllInstancesSansSubclasses("LexDb").First();
				var lexElement = XElement.Parse(lexDto.Xml);
				var lexPossListGuid = GetGuidOfObjSurChild(lexElement.Element("Status"));

				var lexPossListDto = domainObjectDtoRepository.GetDTO(lexPossListGuid);
				var lexPossListElement = XElement.Parse(lexPossListDto.Xml);

				var lexPossList = GetPossibilitiesInList(domainObjectDtoRepository, lexPossListElement).ToList();

				var statusMap = new Dictionary<string, string>();

				// figure out the status substitutions we need to do.
				var langPossibilitiesElt = langPossListElement.Element("Possibilities");
				var lexPossibilitiesElt = lexPossListElement.Element("Possibilities");

				foreach (var lexStatus in lexPossList)
				{
					var nameElt = lexStatus.XPathSelectElement("Name/AUni[@ws='en']");
					var name = nameElt == null ? "" : nameElt.Value; // may have no English name
					if (name == "Approved") name = "Confirmed";
					var lexStatusGuid = lexStatus.Attribute("guid").Value;
					var langStatusGuid = IsStatusInList(langPossList, name);
					if (langStatusGuid == null)
					{
						// Move the old status (LexDb) to the surviving list(LangProj).
						var oldRef = FindObjSurWithGuid(lexPossibilitiesElt, lexStatusGuid);
						oldRef.Remove();
						langPossibilitiesElt.Add(oldRef);
						lexStatus.SetAttributeValue("ownerguid", langPossListGuid);
						UpdateDto(domainObjectDtoRepository, lexStatus);
						// Don't need to put anything in statusMap, we don't need to change refs
						// to a status that is being moved rather than deleted.
					}
					else
					{
						statusMap[lexStatusGuid.ToLowerInvariant()] = langStatusGuid;
						domainObjectDtoRepository.Remove(domainObjectDtoRepository.GetDTO(lexStatusGuid));
					}
				}
				UpdateDto(domainObjectDtoRepository, langPossListDto, langPossListElement);

				// We need to go through tha collection to point all statuses to the LangProj Status list
				foreach (var lexRecDto in domainObjectDtoRepository.AllInstancesSansSubclasses("LexSense").ToArray())
				{
					var lexSenseElement = XElement.Parse(lexRecDto.Xml);
					if (lexSenseElement.Element("Status") != null)
					{
						var statusObjSur = lexSenseElement.Element("Status").Element("objsur");
						var oldStatus = statusObjSur.Attribute("guid").Value;
						string newStatus;
						if (statusMap.TryGetValue(oldStatus.ToLowerInvariant(), out newStatus))
						{
							// We need to update this one.
							statusObjSur.SetAttributeValue("guid", newStatus);
							UpdateDto(domainObjectDtoRepository, lexRecDto, lexSenseElement);
						}
					}
				}
				if (approvedGuid != null)
				{
					// Delete the DTO for the 'Approved' item, and also the objsur that points at it
					// in the possibility list. Hopefully we already fixed all the refs to it.
					domainObjectDtoRepository.Remove(domainObjectDtoRepository.GetDTO(approvedGuid));
					var oldRef = FindObjSurWithGuid(langPossibilitiesElt, approvedGuid);
					oldRef.Remove();
					UpdateDto(domainObjectDtoRepository, langPossListDto, langPossListElement);
				}
				// 6. Delete the CmPossibilityList in LexDb_Status
				domainObjectDtoRepository.Remove(lexPossListDto);
				// 7. Delete the LexDb_Status owning property.
				lexElement.Element("Status").Remove();
				UpdateDto(domainObjectDtoRepository, lexDto, lexElement);
			}
			DataMigrationServices.IncrementVersionNumber(domainObjectDtoRepository);
		}
		private IEnumerable<XElement> GetPossibilitiesInList(IDomainObjectDTORepository domainObjectDtoRepository, XElement langPossListElement)
		{
			return from elt in langPossListElement.XPathSelectElements("Possibilities/objsur")
				   select XElement.Parse(
					domainObjectDtoRepository.GetDTO(elt.Attribute("guid").Value).Xml);
		}
Exemple #36
0
        private void ChangeOwner(IDomainObjectDTORepository repoDTO, DomainObjectDTO dto, string sGuidNew,
                                 string xpathNew)
        {
            XElement   xe       = XElement.Parse(dto.Xml);
            XAttribute xaOwner  = xe.Attribute("ownerguid");
            string     sGuidOld = null;

            if (xaOwner != null)
            {
                sGuidOld = xe.Attribute("ownerguid").Value;
                xe.Attribute("ownerguid").Value = sGuidNew;
            }
            else
            {
                xe.AddAnnotation(new XAttribute("ownerguid", sGuidNew));
            }
            DataMigrationServices.UpdateDTO(repoDTO, dto, xe.ToString());
            if (sGuidOld != null)
            {
                DomainObjectDTO dtoOldOwner = repoDTO.GetDTO(sGuidOld);
                XElement        xeOldOwner  = XElement.Parse(dtoOldOwner.Xml);
#if !__MonoCS__
                string   xpathOld = String.Format(".//objsur[@t='o' and @guid='{0}']", dto.Guid);
                XElement xeOldRef = xeOldOwner.XPathSelectElement(xpathOld);
                if (xeOldRef == null)
                {
                    xpathOld = String.Format(".//objsur[@t='o' and @guid='{0}']", dto.Guid.ToLowerInvariant());
                    xeOldRef = xeOldOwner.XPathSelectElement(xpathOld);
                }
                if (xeOldRef == null)
                {
                    xpathOld = String.Format(".//objsur[@t='o' and @guid='{0}']", dto.Guid.ToUpperInvariant());
                    xeOldRef = xeOldOwner.XPathSelectElement(xpathOld);
                }
                if (xeOldRef == null)
                {
                    foreach (XElement x in xeOldOwner.XPathSelectElements(".//objsur[@t='0']"))
                    {
                        var guidDst = x.Attribute("guid");
                        if (guidDst != null && guidDst.Value.ToLowerInvariant() == dto.Guid.ToLowerInvariant())
                        {
                            xeOldRef = x;
                            break;
                        }
                    }
                }
#else // TODO-Linux: work around mono bug https://bugzilla.novell.com/show_bug.cgi?id=594877
                XElement xeOldRef = null;
                xeOldRef = LocateObjsurElement(xeOldOwner, "o", dto.Guid);
                if (xeOldRef == null)
                {
                    xeOldRef = LocateObjsurElement(xeOldOwner, "0", dto.Guid);
                }
#endif
                if (xeOldRef != null)
                {
                    xeOldRef.Remove();
                    DataMigrationServices.UpdateDTO(repoDTO, dtoOldOwner, xeOldOwner.ToString());
                }
            }
            DomainObjectDTO dtoNewOwner = repoDTO.GetDTO(sGuidNew);
            XElement        xeNewOwner  = XElement.Parse(dtoNewOwner.Xml);
            XElement        xeNewField  = xeNewOwner.XPathSelectElement(xpathNew);
            if (xeNewField == null)
            {
                xeNewField = CreateXPathElementsAsNeeded(xpathNew, xeNewOwner);
            }
            if (xeNewField == null)
            {
                throw new ArgumentException("invalid XPath expression for storing owning objsur element");
            }
            XElement xeObjSur = DataMigrationServices.CreateOwningObjSurElement(dto.Guid);
            if (xeNewField.HasElements)
            {
                xeNewField.LastNode.AddAfterSelf(xeObjSur);
            }
            else
            {
                xeNewField.AddFirst(xeObjSur);
            }
            DataMigrationServices.UpdateDTO(repoDTO, dtoNewOwner, xeNewOwner.ToString());
        }
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Changes the use of CmAgentEvaluation, so that instead of one evaluation per agent/target pair
		/// owned by Agent.Evauations and referring to the target, there are only two CmAgentEvaluations
		/// owned by each CmAgent in their Approves and Disapproves properties, and they are referred to
		/// by the new WfiAnalysis.Evaluations Reference Collection.
		///
		/// Specifically, for each CmAgent,
		/// - Create two CmAgentEvaluations, one owned in Approves and one in Disapproves.
		/// - For each item in Evaluations, if Accepted, add the appropriate Approves evaluation to
		///     the target of the evaluation, otherwise, add the appropriate Disapproves (if there is a target).
		/// - Delete the Evaluations.
		///
		/// As a side effect, since all existing CmAgentEvaluations are deleted, obsolete properties are removed.
		/// </summary>
		/// <param name="domainObjectDtoRepository">Repository of all CmObject DTOs available for
		/// one migration step.</param>
		/// ------------------------------------------------------------------------------------
		public void PerformMigration(IDomainObjectDTORepository domainObjectDtoRepository)
		{
			DataMigrationServices.CheckVersionNumber(domainObjectDtoRepository, 7000013);

			// from guid of a WfiAnalysis to list of evaluations.
			var map = new Dictionary<string, List<string>>();
			foreach (var agentDto in domainObjectDtoRepository.AllInstancesSansSubclasses("CmAgent"))
			{
				var rtElement = XElement.Parse(agentDto.Xml);
				var agentElement = rtElement.Elements("CmAgent").First();
				// Create two new CmAgentEvaluations.
				var newApprovesEval = MakeEvaluation(agentDto.Guid, domainObjectDtoRepository, agentElement, "Approves");
				var newDisapprovesEval = MakeEvaluation(agentDto.Guid, domainObjectDtoRepository, agentElement, "Disapproves");
				var evaluations = agentElement.Elements("Evaluations").FirstOrDefault();
				if (evaluations != null)
				{
					foreach (var objsur in evaluations.Elements("objsur"))
					{
						var evalGuidAttr = objsur.Attribute("guid");
						if (evalGuidAttr == null) continue;

						var evalGuid = evalGuidAttr.Value;
						var obsoleteEvalDto = domainObjectDtoRepository.GetDTO(evalGuid);
						if (obsoleteEvalDto == null)
							continue; // defensive (RandyR says there is no need to be defensive, since the repos will throw an exception, if the guid ois not found.)
						var agentEvalElt = XElement.Parse(obsoleteEvalDto.Xml).Element("CmAgentEvaluation");
						if (agentEvalElt == null)
							continue; // paranoid! (Also, no need for paranoia, since the element *must* be present, or the object cannot be reconstituted.)

						// Delete/Remove the old evaluation.
						domainObjectDtoRepository.Remove(obsoleteEvalDto);

						var acceptedElt = agentEvalElt.Element("Accepted");
						bool accepted = false;
						if (acceptedElt != null)
						{
							var attr = acceptedElt.Attribute("val");
							if (attr != null)
								accepted = attr.Value.ToLowerInvariant() == "true";
						}

						var targetElt = agentEvalElt.Element("Target");
						if (targetElt == null)
							continue;
						var targetObjsur = targetElt.Element("objsur");
						if (targetObjsur == null)
							continue; // paranoid
						var targetGuidAttr = targetObjsur.Attribute("guid");
						if (targetGuidAttr == null)
							continue; // paranoid
						var targetGuid = targetGuidAttr.Value;
						List<String> evals;
						if (!map.TryGetValue(targetGuid, out evals))
						{
							evals = new List<string>();
							map[targetGuid] = evals;
						}

						evals.Add(accepted ? newApprovesEval.Guid : newDisapprovesEval.Guid);
					}
					evaluations.Remove();
				}
				agentDto.Xml = rtElement.ToString();
				domainObjectDtoRepository.Update(agentDto);
			}
			foreach (var kvp in map)
			{
				var analysisDto = domainObjectDtoRepository.GetDTO(kvp.Key);
				var analysisRtElt = XElement.Parse(analysisDto.Xml);
				var analysisElt = analysisRtElt.Element("WfiAnalysis");
				if (analysisElt == null)
					continue; // Paranoid
				var evals = new XElement("Evaluations");
				analysisElt.Add(evals);
				foreach (var eval in kvp.Value)
				{
					evals.Add(new XElement("objsur", new XAttribute("t", "r"), new XAttribute("guid", eval)));
				}
				analysisDto.Xml = analysisRtElt.ToString();
				domainObjectDtoRepository.Update(analysisDto);
			}

			DataMigrationServices.IncrementVersionNumber(domainObjectDtoRepository);
		}
		private static XElement GetPossibilityListNameElement(IDomainObjectDTORepository dtoRepos,
			XElement ownerElement, string flidName)
		{
			Assert.IsNotNull(ownerElement.XPathSelectElement(flidName));
			var xPath = flidName+"/objsur";
			var dto = dtoRepos.GetDTO(ownerElement.XPathSelectElement(xPath).Attribute("guid").Value);
			return XElement.Parse(dto.Xml).XPathSelectElement("Name");
		}
		private static void RemoveDanglingReferences(
			IDomainObjectDTORepository dtoRepos,
			IEnumerable<DomainObjectDTO> allDtos)
		{
			foreach (var currentDto in allDtos)
			{
				 // Fetch the referred (regular reference or owning reference) to object guids.
			   var referredToGuids = ExtractReferencedObjects(currentDto);

				// See if it is a dangling ref, where target object has been deleted.
				foreach (var targetGuid in referredToGuids)
				{
					DomainObjectDTO referencedDto;
					if (dtoRepos.TryGetValue(targetGuid, out referencedDto))
						continue;

					// targetGuid is a dangling reference.
					// Remove the <objsur> element from referring object (kvp Key).
					// The <objsur> will have its 'guid' attribute set to 'targetGuid'.
					// This will work for owned as well as standard referenced objects.
					var targetGuidAsString = targetGuid.ToLower();
					var referringDto = dtoRepos.GetDTO(currentDto.Guid);
					var referringElement = XElement.Parse(referringDto.Xml);
					var emptyPropElements = new List<XElement>();
					foreach (var danglingRef in (referringElement.Descendants("objsur").Where(
						objSurrElement => objSurrElement.Attribute("guid").Value.ToLower() == targetGuidAsString)).ToList())
					{
						var propElement = danglingRef.Parent;
						danglingRef.Remove();
						if (!propElement.HasAttributes && !propElement.HasElements)
							emptyPropElements.Add(propElement);
					}
					foreach (var emptyPropElement in emptyPropElements)
						emptyPropElement.Remove(); // Remove now empty property element.
					// Reset the xml.
					referringDto.Xml = referringElement.ToString();
					dtoRepos.Update(referringDto);
				}
			}
		}
Exemple #40
0
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Combine Sense and Sense Status lists into the Sense list.
        /// </summary>
        /// <param name="domainObjectDtoRepository">
        /// Repository of all CmObject DTOs available for one migration step.
        /// </param>
        /// <remarks>
        /// The method must add/remove/update the DTOs to the repository,
        /// as it adds/removes objects as part of its work.
        ///
        /// Implementors of this interface should ensure the Repository's
        /// starting model version number is correct for the step.
        /// Implementors must also increment the Repository's model version number
        /// at the end of its migration work.
        ///
        /// The method also should normally modify the xml string(s)
        /// of relevant DTOs, since that string will be used by the main
        /// data migration calling client (ie. BEP).
        /// </remarks>
        /// ------------------------------------------------------------------------------------
        public void PerformMigration(IDomainObjectDTORepository domainObjectDtoRepository)
        {
            DataMigrationServices.CheckVersionNumber(domainObjectDtoRepository, 7000023);

            // 1. Change the owning property from LangProject_AnalysisStatus to LangProject_Status

            string statusConfirmedGuid          = "";
            IEnumerable <XElement> langPossList = null;
            var langProjDto     = domainObjectDtoRepository.AllInstancesSansSubclasses("LangProject").First();
            var langProjElement = XElement.Parse(langProjDto.Xml);
            var statusElement   = langProjElement.Element("AnalysisStatus");

            if (statusElement != null)
            {
                statusElement.Name = "Status";
            }
            UpdateDto(domainObjectDtoRepository, langProjDto, langProjElement);

            var langPossListGuid = GetGuidOfObjSurChild(statusElement);

            var langPossListDto     = domainObjectDtoRepository.GetDTO(langPossListGuid);
            var langPossListElement = XElement.Parse(langPossListDto.Xml);

            var langPossListPossibilities = langPossListElement.Element("Possibilities");

            if (langPossListPossibilities == null)
            {
                langPossListElement.Add(XElement.Parse("<Possibilities></Possibilities>"));
                UpdateDto(domainObjectDtoRepository, langPossListDto, langPossListElement);
                // Put the 'Confirmed' status into the list.
                statusConfirmedGuid = MakeStatus(domainObjectDtoRepository, langPossListGuid, langPossListElement,
                                                 "Confirmed", "Conf");
                langPossList = GetPossibilitiesInList(domainObjectDtoRepository, langPossListElement);
                UpdateDto(domainObjectDtoRepository, langPossListDto, langPossListElement);
            }
            else
            {
                // Get the actual elements that represent the possibility items in the AnalysisStatus possibility list.
                langPossList = GetPossibilitiesInList(domainObjectDtoRepository, langPossListElement);

                // 1a.  Verify the 'Confirmed' status exists in the list.
                statusConfirmedGuid = IsStatusInList(langPossList, "Confirmed");
                if (statusConfirmedGuid == null)                 //if not, add it
                {
                    statusConfirmedGuid = MakeStatus(domainObjectDtoRepository, langPossListGuid, langPossListElement,
                                                     "Confirmed", "Conf");
                }
                UpdateDto(domainObjectDtoRepository, langPossListDto, langPossListElement);
            }

            // 1b.  If any rnGeneric records point to the 'Approved' status, point them to 'Confirnmed'.
            var approvedGuid = IsStatusInList(langPossList, "Approved");

            if (approvedGuid != null)
            {
                ReassignStatuses(domainObjectDtoRepository, approvedGuid, statusConfirmedGuid);
            }

            // 2. Get the pointers to the Lexdb Status list (sense status)
            var lexDbElement = langProjElement.Element("LexDb");

            if (lexDbElement != null)
            {
                var lexDto          = domainObjectDtoRepository.AllInstancesSansSubclasses("LexDb").First();
                var lexElement      = XElement.Parse(lexDto.Xml);
                var lexPossListGuid = GetGuidOfObjSurChild(lexElement.Element("Status"));

                var lexPossListDto     = domainObjectDtoRepository.GetDTO(lexPossListGuid);
                var lexPossListElement = XElement.Parse(lexPossListDto.Xml);

                var lexPossList = GetPossibilitiesInList(domainObjectDtoRepository, lexPossListElement).ToList();

                var statusMap = new Dictionary <string, string>();

                // figure out the status substitutions we need to do.
                var langPossibilitiesElt = langPossListElement.Element("Possibilities");
                var lexPossibilitiesElt  = lexPossListElement.Element("Possibilities");

                foreach (var lexStatus in lexPossList)
                {
                    var nameElt = lexStatus.XPathSelectElement("Name/AUni[@ws='en']");
                    var name    = nameElt == null ? "" : nameElt.Value;                  // may have no English name
                    if (name == "Approved")
                    {
                        name = "Confirmed";
                    }
                    var lexStatusGuid  = lexStatus.Attribute("guid").Value;
                    var langStatusGuid = IsStatusInList(langPossList, name);
                    if (langStatusGuid == null)
                    {
                        // Move the old status (LexDb) to the surviving list(LangProj).
                        var oldRef = FindObjSurWithGuid(lexPossibilitiesElt, lexStatusGuid);
                        oldRef.Remove();
                        langPossibilitiesElt.Add(oldRef);
                        lexStatus.SetAttributeValue("ownerguid", langPossListGuid);
                        UpdateDto(domainObjectDtoRepository, lexStatus);
                        // Don't need to put anything in statusMap, we don't need to change refs
                        // to a status that is being moved rather than deleted.
                    }
                    else
                    {
                        statusMap[lexStatusGuid.ToLowerInvariant()] = langStatusGuid;
                        domainObjectDtoRepository.Remove(domainObjectDtoRepository.GetDTO(lexStatusGuid));
                    }
                }
                UpdateDto(domainObjectDtoRepository, langPossListDto, langPossListElement);

                // We need to go through tha collection to point all statuses to the LangProj Status list
                foreach (var lexRecDto in domainObjectDtoRepository.AllInstancesSansSubclasses("LexSense").ToArray())
                {
                    var lexSenseElement = XElement.Parse(lexRecDto.Xml);
                    if (lexSenseElement.Element("Status") != null)
                    {
                        var    statusObjSur = lexSenseElement.Element("Status").Element("objsur");
                        var    oldStatus    = statusObjSur.Attribute("guid").Value;
                        string newStatus;
                        if (statusMap.TryGetValue(oldStatus.ToLowerInvariant(), out newStatus))
                        {
                            // We need to update this one.
                            statusObjSur.SetAttributeValue("guid", newStatus);
                            UpdateDto(domainObjectDtoRepository, lexRecDto, lexSenseElement);
                        }
                    }
                }
                if (approvedGuid != null)
                {
                    // Delete the DTO for the 'Approved' item, and also the objsur that points at it
                    // in the possibility list. Hopefully we already fixed all the refs to it.
                    domainObjectDtoRepository.Remove(domainObjectDtoRepository.GetDTO(approvedGuid));
                    var oldRef = FindObjSurWithGuid(langPossibilitiesElt, approvedGuid);
                    oldRef.Remove();
                    UpdateDto(domainObjectDtoRepository, langPossListDto, langPossListElement);
                }
                // 6. Delete the CmPossibilityList in LexDb_Status
                domainObjectDtoRepository.Remove(lexPossListDto);
                // 7. Delete the LexDb_Status owning property.
                lexElement.Element("Status").Remove();
                UpdateDto(domainObjectDtoRepository, lexDto, lexElement);
            }
            DataMigrationServices.IncrementVersionNumber(domainObjectDtoRepository);
        }
		/// <summary>
		/// 1. Create the "Strong" style if it doesn't exist (FWR-741).
		/// 2. Convert direct formatting to styles (FWR-648).
		/// 3. Move the StStyle objects in LexDb.Styles to LangProject.Styles, deleting those
		///	   with the same name as one already in LangProject.Styles (FWR-1163).
		///	4. Delete the Styles field from LexDb (FWR-1163).
		///	5. Remove "External Link" and "Internal Link" styles - migrate use of these to
		///	   "Hyperlink" style (FWR-1163).
		///	6. Rename "Language Code" style to "Writing System Abbreviation" (FWR-1163).
		///	7. Ensure that built-in styles from LangProject.Styles are marked built-in.
		/// </summary>
		public void PerformMigration(IDomainObjectDTORepository repoDTO)
		{
			m_repoDTO = repoDTO;
			// Get the list of StStyle DTOs from the LexDb.Styles field, and delete the
			// LexDb.Styles field.
			string sClass = "LexDb";
			DomainObjectDTO dtoLexDb = GetFirstInstance(sClass);
			string sXmlLexDb = dtoLexDb.Xml;
			int idxStyles = sXmlLexDb.IndexOf("<Styles>");
			int idxStylesLim = sXmlLexDb.IndexOf("</Styles>") + 9;
			string sLexDbStyles = sXmlLexDb.Substring(idxStyles, idxStylesLim - idxStyles);
			List<DomainObjectDTO> stylesLexDb = new List<DomainObjectDTO>();
			foreach (string sGuid in GetGuidList(sLexDbStyles))
			{
				var dto = m_repoDTO.GetDTO(sGuid);
				stylesLexDb.Add(dto);
			}
			dtoLexDb.Xml = sXmlLexDb.Remove(idxStyles, idxStylesLim - idxStyles);
			m_repoDTO.Update(dtoLexDb);

			// Get the list of StStyle DTOs (and style names) from the LangProject.Styles field.
			m_dtoLangProj = GetFirstInstance("LangProject");
			string sXmlLangProj = m_dtoLangProj.Xml;
			idxStyles = sXmlLangProj.IndexOf("<Styles>");
			idxStylesLim = sXmlLangProj.IndexOf("</Styles>") + 9;
			m_sLangProjStyles = sXmlLangProj.Substring(idxStyles, idxStylesLim - idxStyles);
			string sLangProjStylesOrig = m_sLangProjStyles;
			int idxEnd = m_sLangProjStyles.Length - 9;
			List<string> styleNames = new List<string>();
			m_langProjStyles.Clear();
			m_mapStyleNameToGuid.Clear();
			DomainObjectDTO dtoHyperlink = null;
			DomainObjectDTO dtoExternalLink = null;
			DomainObjectDTO dtoInternalLink = null;
			DomainObjectDTO dtoLanguageCode = null;
			DomainObjectDTO dtoWrtSysAbbr = null;
			DomainObjectDTO dtoStrong = null;
			foreach (string sGuid in GetGuidList(m_sLangProjStyles))
			{
				var dto = m_repoDTO.GetDTO(sGuid);
				string sName = GetStyleName(dto.Xml);
				styleNames.Add(sName);
				m_langProjStyles.Add(dto);
				m_mapStyleNameToGuid.Add(sName, dto.Guid.ToLowerInvariant());
				switch (sName)
				{
					case "Hyperlink":
						dtoHyperlink = dto;
						break;
					case "External Link":
						dtoExternalLink = dto;
						break;
					case "Internal Link":
						dtoInternalLink = dto;
						break;
					case "Language Code":
						dtoLanguageCode = dto;
						break;
					case "Writing System Abbreviation":
						dtoWrtSysAbbr = dto;
						break;
					case "Strong":
						dtoStrong = dto;
						break;
				}
			}
			var mapLexDbStyleGuidName = new Dictionary<string, string>();
			// For each style in the ones we might delete we need to know the name of the style it is based on and its next style
			foreach (var dto in stylesLexDb)
			{
				var elt = XElement.Parse(dto.Xml);
				var name = elt.Element("Name").Element("Uni").Value;
				mapLexDbStyleGuidName[dto.Guid] = name;
			}
			Dictionary<string, string> mapStyleGuids = new Dictionary<string, string>();
			foreach (var dto in stylesLexDb)
			{
				string sXml = dto.Xml;
				string sName = GetStyleName(sXml);
				if (styleNames.Contains(sName))
				{
					var keeperGuid = m_mapStyleNameToGuid[sName];
					mapStyleGuids.Add(dto.Guid.ToLowerInvariant(), keeperGuid);
					// Duplicate between Notebook (LangProj) styles already in the dictionary,
					// and Lexicon (LexDb) ones being added. Discard the Lexicon style OBJECT, but keep its rules.
					var dtoKeeper = repoDTO.GetDTO(keeperGuid);
					var keeperElement = XElement.Parse(dtoKeeper.Xml);
					var dropElement = XElement.Parse(dto.Xml);
					var rules = dropElement.Element("Rules");
					if (rules != null)
					{
						var oldRules = keeperElement.Element("Rules");
						oldRules.ReplaceWith(rules);
					}
					UpdateStyleCrossReference(mapLexDbStyleGuidName, dropElement, keeperElement, "BasedOn");
					UpdateStyleCrossReference(mapLexDbStyleGuidName, dropElement, keeperElement, "Next");
					dtoKeeper.Xml = keeperElement.ToString();
					repoDTO.Update(dtoKeeper);
					m_repoDTO.Remove(dto);
				}
				else
				{
					// change the ownership links
					m_sLangProjStyles = m_sLangProjStyles.Insert(idxEnd, string.Format("<objsur guid=\"{0}\" t=\"o\"/>{1}", dto.Guid, Environment.NewLine));
					idxEnd = m_sLangProjStyles.Length - 9;
					SetOwnerGuid(dto, m_dtoLangProj.Guid);
					switch (sName)
					{
						case "Hyperlink":					dtoHyperlink = dto;		break;
						case "External Link":				dtoExternalLink = dto;	break;
						case "Internal Link":				dtoInternalLink = dto;	break;
						case "Language Code":				dtoLanguageCode = dto;	break;
						case "Writing System Abbreviation":	dtoWrtSysAbbr = dto;	break;
						case "Strong":						dtoStrong = dto;		break;
					}
					styleNames.Add(sName);
					m_langProjStyles.Add(dto);
					m_mapStyleNameToGuid.Add(sName, dto.Guid.ToLowerInvariant());
				}
			}
			// if "Hyperlink" does not exist, create it.
			if (dtoHyperlink == null)
			{
				dtoHyperlink = CreateCharStyle("Hyperlink",
					"<Prop forecolor=\"blue\" undercolor=\"blue\" underline=\"single\" />",
					ContextValues.Internal);
				m_langProjStyles.Add(dtoHyperlink);
				m_mapStyleNameToGuid.Add("Hyperlink", dtoHyperlink.Guid.ToLowerInvariant());
			}
			else
			{
				// ensure that the Hyperlink style has an "internal" context.
				string sXml = dtoHyperlink.Xml;
				int idx = sXml.IndexOf("<Context");
				if (idx > 0)
				{
					XElement xeHyper = XElement.Parse(sXml);
					foreach (XElement xe in xeHyper.Descendants("Context"))
					{
						int nVal;
						XAttribute xa = xe.Attribute("val");
						if (xa != null && Int32.TryParse(xa.Value, out nVal) && nVal != (int)ContextValues.Internal)
						{
							nVal = (int)ContextValues.Internal;
							xa.Value = nVal.ToString();
							dtoHyperlink.Xml = xeHyper.ToString();
							m_repoDTO.Update(dtoHyperlink);
							break;
						}
					}
				}
			}
			// delete "External Link" and "Internal Link", and prepare to replace links to
			// them with a link to "Hyperlink".
			if (dtoExternalLink != null)
			{
				mapStyleGuids.Add(dtoExternalLink.Guid.ToLowerInvariant(), dtoHyperlink.Guid.ToLowerInvariant());
				m_sLangProjStyles = DeleteStyle(m_sLangProjStyles, dtoExternalLink);
				m_mapStyleNameToGuid["External Link"] = dtoHyperlink.Guid.ToLowerInvariant();
			}
			if (dtoInternalLink != null)
			{
				mapStyleGuids.Add(dtoInternalLink.Guid.ToLowerInvariant(), dtoHyperlink.Guid.ToLowerInvariant());
				m_sLangProjStyles = DeleteStyle(m_sLangProjStyles, dtoInternalLink);
				m_mapStyleNameToGuid["Internal Link"] = dtoHyperlink.Guid.ToLowerInvariant();
			}
			if (dtoLanguageCode == null)
			{
				// If neither "Language Code" nor "Writing System Abbreviation" exist, create the
				// "Writing System Abbreviation" style.
				if (dtoWrtSysAbbr == null)
				{
					dtoWrtSysAbbr = CreateCharStyle("Writing System Abbreviation",
						"<Prop fontsize=\"8000\" fontsizeUnit=\"mpt\" forecolor=\"2f60ff\" />",
						ContextValues.General);
					m_langProjStyles.Add(dtoWrtSysAbbr);
					m_mapStyleNameToGuid.Add("Writing System Abbreviation", dtoWrtSysAbbr.Guid.ToLowerInvariant());
				}
				else
				{
					// We don't need to do anything.
				}
			}
			else
			{
				if (dtoWrtSysAbbr == null)
				{
					// Rename "Language Code" to "Writing System Abbreviation".
					string sXml = dtoLanguageCode.Xml;
					dtoLanguageCode.Xml = sXml.Replace("<Uni>Language Code</Uni>",
						"<Uni>Writing System Abbreviation</Uni>");
					m_repoDTO.Update(dtoLanguageCode);
					m_mapStyleNameToGuid.Add("Writing System Abbreviation", dtoLanguageCode.Guid.ToLowerInvariant());
				}
				else
				{
					// delete "Language Code", and prepare to replace links to it with a link to
					// "Writing System Abbreviation".
					mapStyleGuids.Add(dtoLanguageCode.Guid.ToLowerInvariant(), dtoWrtSysAbbr.Guid.ToLowerInvariant());
					m_sLangProjStyles = DeleteStyle(m_sLangProjStyles, dtoLanguageCode);
					m_mapStyleNameToGuid["Language Code"] = dtoWrtSysAbbr.Guid.ToLowerInvariant();
				}
			}
			// if "Strong" does not exist, create it.
			if (dtoStrong == null)
			{
				dtoStrong = CreateCharStyle("Strong", "<Prop bold=\"invert\" />", ContextValues.General);
				m_langProjStyles.Add(dtoStrong);
				m_mapStyleNameToGuid.Add("Strong", dtoStrong.Guid.ToLowerInvariant());
			}
			ChangeStyleReferences();
			UpdateStyleLinks(mapStyleGuids);
			ReplaceDirectFormattingWithStyles();
			EnsureBuiltinStylesAreMarkedBuiltin();

			if (m_sLangProjStyles != sLangProjStylesOrig)
			{
				sXmlLangProj = sXmlLangProj.Remove(idxStyles, idxStylesLim - idxStyles);
				m_dtoLangProj.Xml = sXmlLangProj.Insert(idxStyles, m_sLangProjStyles);
				m_repoDTO.Update(m_dtoLangProj);
			}

			DataMigrationServices.IncrementVersionNumber(m_repoDTO);
		}
		private static void CheckNotes(IDomainObjectDTORepository dtoRepos, DomainObjectDTO newSegmentDto, ICollection noteGuids, XContainer newSegmentInnerElement, bool expectedToHaveNotes, int expectedNumberOfNotes)
		{
			// Check Nts.
			var notesElements = newSegmentInnerElement.Elements("Notes");
			if (!expectedToHaveNotes)
			{
				Assert.AreEqual(0, notesElements.Count(), "Had unexpected number of notes.");
				return;
			}

			var objsurElements = notesElements.Elements("objsur");
			Assert.AreEqual(expectedNumberOfNotes, objsurElements.Count(), "Wrong number of Notes.");
			foreach (var objsurElement in objsurElements)
			{
				// Make sure the objsur guid is in 'noteGuids'.
				var objsurGuid = objsurElement.Attribute("guid").Value;
				Assert.Contains(objsurGuid, noteGuids);

				// Make sure the objsur element is t="o" (owning).
				var type = objsurElement.Attribute("t").Value;
				Assert.AreEqual("o", type, "Not an owning property.");

				// Make sure the owner of the objsur guid is the new Segment.
				var noteDto = dtoRepos.GetDTO(objsurGuid);
				Assert.AreSame(newSegmentDto, dtoRepos.GetOwningDTO(noteDto));

				// Each Nt should have two alts.
				var noteElement = XElement.Parse(noteDto.Xml);
				var contentElement = noteElement.Element("Note").Element("Content");
				Assert.IsNotNull(contentElement, "No Nt Content element.");
				CheckAlternatives(contentElement, 2);
			}
		}
		private static DomainObjectDTO GetDTOIfItExists(IDomainObjectDTORepository dtoRepository, string sGuid)
		{
			try
			{
				return dtoRepository.GetDTO(sGuid);
			}
			catch (ArgumentException)
			{
				return null;
			}
		}
		private static void CheckCCR(
			IDomainObjectDTORepository dtoRepos,
			XElement rowObjSurElement,
			string notes,
			string label,
			string clauseType,
			string endParagraph,
			string endSentence,
			string startDep,
			string endDep,
			int cellsCount)
		{
			var currentCCRElement = XElement.Parse(
				dtoRepos.GetDTO(rowObjSurElement.Attribute("guid").Value).Xml);
			var innerConstChartRowElement = currentCCRElement.Element("ConstChartRow");
			if (notes == null)
				Assert.IsNull(innerConstChartRowElement.Element("Notes"), "Has Notes.");
			else
				Assert.AreEqual(notes, innerConstChartRowElement.Element("Notes").Value, "Wrong Notes.");
			Assert.AreEqual(label, innerConstChartRowElement.Element("Label").Value, "Wrong Label.");
			Assert.AreEqual(clauseType, innerConstChartRowElement.Element("ClauseType").Attribute("val").Value, "Wrong ClauseType.");
			Assert.AreEqual(endParagraph, innerConstChartRowElement.Element("EndParagraph").Attribute("val").Value.ToLower(), "Wrong EndParagraph.");
			Assert.AreEqual(endSentence, innerConstChartRowElement.Element("EndSentence").Attribute("val").Value.ToLower(), "Wrong EndSentence.");
			Assert.AreEqual(startDep, innerConstChartRowElement.Element("StartDependentClauseGroup").Attribute("val").Value.ToLower(), "Wrong StartDependentClauseGroup.");
			Assert.AreEqual(endDep, innerConstChartRowElement.Element("EndDependentClauseGroup").Attribute("val").Value.ToLower(), "Wrong EndDependentClauseGroup.");
			var cellsElement = innerConstChartRowElement.Element("Cells");
			if (cellsCount == 0)
				Assert.IsNull(cellsElement, "Has Cells.");
			else
				Assert.AreEqual(cellsCount, cellsElement.Elements("objsur").Count(), "Wrong cell count.");
		}
		private void ChangeOwner(IDomainObjectDTORepository repoDTO, DomainObjectDTO dto, string sGuidNew,
			string xpathNew)
		{
			XElement xe = XElement.Parse(dto.Xml);
			XAttribute xaOwner = xe.Attribute("ownerguid");
			string sGuidOld = null;
			if (xaOwner != null)
			{
				sGuidOld = xe.Attribute("ownerguid").Value;
				xe.Attribute("ownerguid").Value = sGuidNew;
			}
			else
			{
				xe.AddAnnotation(new XAttribute("ownerguid", sGuidNew));
			}
			DataMigrationServices.UpdateDTO(repoDTO, dto, xe.ToString());
			if (sGuidOld != null)
			{
				DomainObjectDTO dtoOldOwner = repoDTO.GetDTO(sGuidOld);
				XElement xeOldOwner = XElement.Parse(dtoOldOwner.Xml);
#if !__MonoCS__
				string xpathOld = String.Format(".//objsur[@t='o' and @guid='{0}']", dto.Guid);
				XElement xeOldRef = xeOldOwner.XPathSelectElement(xpathOld);
				if (xeOldRef == null)
				{
					xpathOld = String.Format(".//objsur[@t='o' and @guid='{0}']", dto.Guid.ToLowerInvariant());
					xeOldRef = xeOldOwner.XPathSelectElement(xpathOld);
				}
				if (xeOldRef == null)
				{
					xpathOld = String.Format(".//objsur[@t='o' and @guid='{0}']", dto.Guid.ToUpperInvariant());
					xeOldRef = xeOldOwner.XPathSelectElement(xpathOld);
				}
				if (xeOldRef == null)
				{
					foreach (XElement x in xeOldOwner.XPathSelectElements(".//objsur[@t='0']"))
					{
						var guidDst = x.Attribute("guid");
						if (guidDst != null && guidDst.Value.ToLowerInvariant() == dto.Guid.ToLowerInvariant())
						{
							xeOldRef = x;
							break;
						}
					}
				}
#else // TODO-Linux: work around mono bug https://bugzilla.novell.com/show_bug.cgi?id=594877
				XElement xeOldRef = null;
				xeOldRef = LocateObjsurElement(xeOldOwner, "o", dto.Guid);
				if (xeOldRef == null)
						xeOldRef = LocateObjsurElement(xeOldOwner, "0", dto.Guid);
#endif
				if (xeOldRef != null)
				{
					xeOldRef.Remove();
					DataMigrationServices.UpdateDTO(repoDTO, dtoOldOwner, xeOldOwner.ToString());
				}
			}
			DomainObjectDTO dtoNewOwner = repoDTO.GetDTO(sGuidNew);
			XElement xeNewOwner = XElement.Parse(dtoNewOwner.Xml);
			XElement xeNewField = xeNewOwner.XPathSelectElement(xpathNew);
			if (xeNewField == null)
				xeNewField = CreateXPathElementsAsNeeded(xpathNew, xeNewOwner);
			if (xeNewField == null)
				throw new ArgumentException("invalid XPath expression for storing owning objsur element");
			XElement xeObjSur = DataMigrationServices.CreateOwningObjSurElement(dto.Guid);
			if (xeNewField.HasElements)
				xeNewField.LastNode.AddAfterSelf(xeObjSur);
			else
				xeNewField.AddFirst(xeObjSur);
			DataMigrationServices.UpdateDTO(repoDTO, dtoNewOwner, xeNewOwner.ToString());
		}
Exemple #46
0
        /// <summary>
        /// Updates the Data Notebook RecordTypes possibilities to use specific GUIDs.
        /// </summary>
        /// <param name="domainObjectDtoRepository">Repository of all CmObject DTOs available for one migration step.</param>
        public void PerformMigration(IDomainObjectDTORepository domainObjectDtoRepository)
        {
            DataMigrationServices.CheckVersionNumber(domainObjectDtoRepository, 7000010);

            DomainObjectDTO nbkDto                    = domainObjectDtoRepository.AllInstancesSansSubclasses("RnResearchNbk").First();
            XElement        nbkElem                   = XElement.Parse(nbkDto.Xml);
            var             recTypesGuid              = (string)nbkElem.XPathSelectElement("RnResearchNbk/RecTypes/objsur").Attribute("guid");
            var             stack                     = new Stack <DomainObjectDTO>(domainObjectDtoRepository.GetDirectlyOwnedDTOs(recTypesGuid));
            IEnumerable <DomainObjectDTO> recDtos     = domainObjectDtoRepository.AllInstancesSansSubclasses("RnGenericRec");
            IEnumerable <DomainObjectDTO> overlayDtos = domainObjectDtoRepository.AllInstancesSansSubclasses("CmOverlay");

            while (stack.Count > 0)
            {
                DomainObjectDTO dto = stack.Pop();
                foreach (DomainObjectDTO childDto in domainObjectDtoRepository.GetDirectlyOwnedDTOs(dto.Guid))
                {
                    stack.Push(childDto);
                }
                XElement posElem = XElement.Parse(dto.Xml);
                XElement uniElem = posElem.XPathSelectElement("CmPossibility/Abbreviation/AUni[@ws='en']");
                if (uniElem != null)
                {
                    string newGuid = null;
                    switch (uniElem.Value)
                    {
                    case "Con":
                        newGuid = "B7B37B86-EA5E-11DE-80E9-0013722F8DEC";
                        break;

                    case "Intv":
                        newGuid = "B7BF673E-EA5E-11DE-9C4D-0013722F8DEC";
                        break;

                    case "Str":
                        newGuid = "B7C8F092-EA5E-11DE-8D7D-0013722F8DEC";
                        break;

                    case "Uns":
                        newGuid = "B7D4DC4A-EA5E-11DE-867C-0013722F8DEC";
                        break;

                    case "Lit":
                        newGuid = "B7E0C7F8-EA5E-11DE-82CC-0013722F8DEC";
                        break;

                    case "Obs":
                        newGuid = "B7EA5156-EA5E-11DE-9F9C-0013722F8DEC";
                        break;

                    case "Per":
                        newGuid = "B7F63D0E-EA5E-11DE-9F02-0013722F8DEC";
                        break;

                    case "Ana":
                        newGuid = "82290763-1633-4998-8317-0EC3F5027FBD";
                        break;
                    }
                    if (newGuid != null)
                    {
                        DataMigrationServices.ChangeGuid(domainObjectDtoRepository, dto, newGuid, recDtos.Concat(overlayDtos));
                    }
                }
            }

            DomainObjectDTO recTypesDto = domainObjectDtoRepository.GetDTO(recTypesGuid);

            DataMigrationServices.ChangeGuid(domainObjectDtoRepository, recTypesDto, "D9D55B12-EA5E-11DE-95EF-0013722F8DEC", overlayDtos);
            DataMigrationServices.IncrementVersionNumber(domainObjectDtoRepository);
        }
		private static XElement CheckNewSegment(IDomainObjectDTORepository dtoRepos, int beginOffset, DomainObjectDTO owningPara, XElement newSegmentObjSurElement, out DomainObjectDTO newSegmentDto)
		{
			newSegmentDto = dtoRepos.GetDTO(newSegmentObjSurElement.Attribute("guid").Value);
			Assert.IsNotNull(newSegmentDto, "Missing new Segment DTO.");
			var newSegmentElement = XElement.Parse(newSegmentDto.Xml);
			// Make sure it is owned by the expected para.
			Assert.AreSame(owningPara, dtoRepos.GetOwningDTO(newSegmentDto), "Wrong paragraph owner.");
			var newSegmentInnerElement = newSegmentElement.Element("Segment");
			Assert.IsNotNull(newSegmentInnerElement, "Missing new inner Segment Element in the new Segment object.");
			Assert.AreEqual(beginOffset, int.Parse(newSegmentInnerElement.Element("BeginOffset").Attribute("val").Value));

			return newSegmentInnerElement;
		}
		// I think this is roughly what we need to reinstate if we reinstate the call to it. See comments there.
		//private static void FillWritingSystemFromLangDef(XElement langDefElem, Version19WritingSystemDefn ws)
		//{
		//    XElement wsElem = langDefElem.Element("LgWritingSystem");
		//    if (wsElem != null)
		//    {
		//        string name = GetMultiUnicode(wsElem, "Name24");
		//        if (!string.IsNullOrEmpty(name))
		//        {
		//            int parenIndex = name.IndexOf('(');
		//            if (parenIndex != -1)
		//                name = name.Substring(0, parenIndex).Trim();
		//            ws.LanguageName = name;
		//        }

		//        string abbr = GetMultiUnicode(wsElem, "Abbr24");
		//        if (!string.IsNullOrEmpty(abbr))
		//            ws.Abbreviation = abbr;
		//        XElement collsElem = wsElem.Element("Collations24");
		//        if (collsElem != null)
		//        {
		//            XElement collElem = collsElem.Element("LgCollation");
		//            if (collElem != null)
		//            {
		//                string icuRules = GetUnicode(collElem, "ICURules30");
		//                if (!string.IsNullOrEmpty(icuRules))
		//                {
		//                    ws.SortUsing = WritingSystemDefinition.SortRulesType.CustomICU;
		//                    ws.SortRules = icuRules;
		//                }
		//            }
		//        }
		//        string defFont = GetUnicode(wsElem, "DefaultSerif24");
		//        if (!string.IsNullOrEmpty(defFont))
		//            ws.DefaultFontName = defFont;
		//        string defFontFeats = GetUnicode(wsElem, "FontVariation24");
		//        if (!string.IsNullOrEmpty(defFontFeats))
		//            ws.DefaultFontFeatures = defFontFeats;
		//        string keyboard = GetUnicode(wsElem, "KeymanKeyboard24");
		//        if (!string.IsNullOrEmpty(keyboard))
		//            ws.Keyboard = keyboard;
		//        string legacyMapping = GetUnicode(wsElem, "LegacyMapping24");
		//        if (!string.IsNullOrEmpty(legacyMapping))
		//            ws.LegacyMapping = legacyMapping;
		//        XElement localeElem = wsElem.Element("Locale24");
		//        if (localeElem != null)
		//        {
		//            XElement intElem = localeElem.Element("Integer");
		//            if (intElem != null)
		//                ws.LCID = (int) intElem.Attribute("val");
		//        }
		//        string matchedPairs = GetUnicode(wsElem, "MatchedPairs24");
		//        if (!string.IsNullOrEmpty(matchedPairs))
		//            ws.MatchedPairs = matchedPairs;
		//        string punctPatterns = GetUnicode(wsElem, "PunctuationPatterns24");
		//        if (!string.IsNullOrEmpty(punctPatterns))
		//            ws.PunctuationPatterns = punctPatterns;
		//        string quotMarks = GetUnicode(wsElem, "QuotationMarks24");
		//        if (!string.IsNullOrEmpty(quotMarks))
		//            ws.QuotationMarks = quotMarks;
		//        XElement rtolElem = wsElem.Element("RightToLeft24");
		//        if (rtolElem != null)
		//        {
		//            XElement boolElem = rtolElem.Element("Boolean");
		//            if (boolElem != null)
		//                ws.RightToLeftScript = (bool) boolElem.Attribute("val");
		//        }
		//        string spellCheck = GetUnicode(wsElem, "SpellCheckDictionary24");
		//        if (!string.IsNullOrEmpty(spellCheck))
		//            ws.SpellCheckingId = spellCheck;
		//        string validChars = GetUnicode(wsElem, "ValidChars24");
		//        if (!string.IsNullOrEmpty(validChars))
		//            ws.ValidChars = Icu.Normalize(validChars, Icu.UNormalizationMode.UNORM_NFD);
		//    }

		//    var localeName = (string) langDefElem.Element("LocaleName");
		//    if (!string.IsNullOrEmpty(localeName))
		//    {
		//        ws.LanguageName = localeName;
		//    }
		//    var scriptName = (string)langDefElem.Element("LocaleScript");
		//    if (!string.IsNullOrEmpty(scriptName))
		//    {
		//        ws.ScriptName = scriptName;
		//    }
		//    var regionName = (string)langDefElem.Element("LocaleCountry");
		//    if (!string.IsNullOrEmpty(regionName))
		//    {
		//        ws.RegionName = regionName;
		//    }
		//    var variantName = (string) langDefElem.Element("LocaleVariant");
		//    if (!string.IsNullOrEmpty(variantName))
		//    {
		//            ws.VariantName = variantName;
		//    }
		//}

		private static void FillWritingSystemFromFDO(IDomainObjectDTORepository domainObjectDtoRepository,
			XElement wsElem, Version19WritingSystemDefn ws)
		{
			string name = GetMultiUnicode(wsElem, "Name");
			if (!string.IsNullOrEmpty(name))
			{
				int parenIndex = name.IndexOf('(');
				if (parenIndex != -1)
					name = name.Substring(0, parenIndex).Trim();
				ws.LanguageName = name;
			}
			string abbr = GetMultiUnicode(wsElem, "Abbr");
			if (!string.IsNullOrEmpty(abbr))
				ws.Abbreviation = abbr;
			string defFont = GetUnicode(wsElem, "DefaultSerif");
			if (!string.IsNullOrEmpty(defFont))
				ws.DefaultFontName = defFont;
			string defFontFeats = GetUnicode(wsElem, "FontVariation");
			if (!string.IsNullOrEmpty(defFontFeats))
				ws.DefaultFontFeatures = defFontFeats;
			string keyboard = GetUnicode(wsElem, "KeymanKeyboard");
			if (!string.IsNullOrEmpty(keyboard))
				ws.Keyboard = keyboard;
			string legacyMapping = GetUnicode(wsElem, "LegacyMapping");
			if (!string.IsNullOrEmpty(legacyMapping))
				ws.LegacyMapping = legacyMapping;
			XElement localeElem = wsElem.Element("Locale");
			if (localeElem != null)
				ws.LCID = (int) localeElem.Attribute("val");
			string matchedPairs = GetUnicode(wsElem, "MatchedPairs");
			if (!string.IsNullOrEmpty(matchedPairs))
				ws.MatchedPairs = matchedPairs;
			string puncPatterns = GetUnicode(wsElem, "PunctuationPatterns");
			if (!string.IsNullOrEmpty(puncPatterns))
				ws.PunctuationPatterns = puncPatterns;
			string quotMarks = GetUnicode(wsElem, "QuotationMarks");
			if (!string.IsNullOrEmpty(quotMarks))
				ws.QuotationMarks = quotMarks;
			XElement rtolElem = wsElem.Element("RightToLeft");
			if (rtolElem != null)
				ws.RightToLeftScript = (bool) rtolElem.Attribute("val");
			string spellCheck = GetUnicode(wsElem, "SpellCheckDictionary");
			if (!string.IsNullOrEmpty(spellCheck))
				ws.SpellCheckingId = spellCheck;
			string validChars = GetUnicode(wsElem, "ValidChars");
			if (!string.IsNullOrEmpty(validChars))
				ws.ValidChars = Icu.Normalize(validChars, Icu.UNormalizationMode.UNORM_NFD);

			XElement collsElem = wsElem.Element("Collations");
			if (collsElem != null)
			{
				XElement surElem = collsElem.Element("objsur");
				if (surElem != null)
				{
					var guid = (string) surElem.Attribute("guid");
					DomainObjectDTO collDto = domainObjectDtoRepository.GetDTO(guid);
					XElement collElem = XElement.Parse(collDto.Xml);
					string sortRules = GetUnicode(collElem, "ICURules");
					if (!string.IsNullOrEmpty(sortRules))
					{
						ws.SortUsing = WritingSystemDefinition.SortRulesType.CustomICU;
						ws.SortRules = sortRules;
					}
				}
			}
		}
		private bool IsWeatherUsed(IDomainObjectDTORepository repoDTO, List<DomainObjectDTO> collectOverlaysToRemove)
		{
			DomainObjectDTO dtoLP = GetDtoLangProj(repoDTO);
			string sLpXml = dtoLP.Xml;
			int idxW = sLpXml.IndexOf("<WeatherConditions>");
			var sguidWeather = ExtractFirstGuid(sLpXml, idxW, " guid=\"");
			DomainObjectDTO dtoWeather = repoDTO.GetDTO(sguidWeather);
			var weatherItems = new HashSet<string>();
			CollectItems(repoDTO, dtoWeather, weatherItems);
			foreach (var dto in repoDTO.AllInstancesWithSubclasses("RnGenericRec"))
			{
				string sXml = dto.Xml;
				int idx = sXml.IndexOf("<Weather>");
				if (idx > 0)
				{
					int idxEnd = sXml.IndexOf("</Weather>");
					if (idxEnd > idx)
					{
						string s = sXml.Substring(idx, idxEnd - idx);
						if (s.Contains("<objsur "))
						{
							return true;
						}
					}
				}
				bool dummy = false;
				if (StringContainsRefToItemInList("PhraseTags", weatherItems, sXml, ref dummy)) return true;
			}
			foreach (var dto in repoDTO.AllInstancesSansSubclasses("CmOverlay"))
			{
				string sXml = dto.Xml;
				bool hasOtherItems = false;
				bool hasWeatherRef = StringContainsRefToItemInList("PossItems", weatherItems, sXml, ref hasOtherItems);
				var weatherListSet = new HashSet<string>();
				weatherListSet.Add(sguidWeather.ToLowerInvariant());
				hasWeatherRef |= StringContainsRefToItemInList("PossList", weatherListSet, sXml, ref hasOtherItems);
				if (hasWeatherRef)
				{
					if (hasOtherItems)
						return true; // an overlay with a mixture of weather and non-weather items is a problem
					// One with only weather refs (and not used, since we know nothing is tagged to weather)
					// will be deleted.
					collectOverlaysToRemove.Add(dto);
				}
			}
			return false;
		}
		private void RemoveInvalidFiles(IDomainObjectDTORepository repoDto,
			DomainObjectDTO langProj, DomainObjectDTO folder)
		{
			var langProjElement = XElement.Parse(langProj.Xml);
			var pictures = langProjElement.Element("Pictures");
			var fileMap = CreateFilePathToGuidMap(repoDto, folder);
			var pictureMap = CreateFileGuidToPictureMap(repoDto);
			foreach (var x in pictures.Elements())
			{
				var xObj = repoDto.GetDTO(x.Attribute("guid").Value);
				if (xObj.Classname == "CmFile")
				{
					string replacementFileGuid;
					string filePath = GetFilePath(xObj);
					if (filePath != null &&
						fileMap.TryGetValue(filePath.ToLowerInvariant(), out replacementFileGuid))
					{
						UpdatePictureReferences(repoDto, xObj, replacementFileGuid, pictureMap);
						DataMigrationServices.RemoveIncludingOwnedObjects(repoDto, xObj, true);
					}
					else if (!pictureMap.ContainsKey(xObj.Guid))
						DataMigrationServices.RemoveIncludingOwnedObjects(repoDto, xObj, true);
					else
					{
						MoveFileToFolder(repoDto, folder, xObj);
						RemoveReferenceFromPictures(repoDto, langProj, xObj.Guid);
					}
				}
			}
		}
        public void PerformMigration(IDomainObjectDTORepository domainObjectDtoRepository)
        {
            DataMigrationServices.CheckVersionNumber(domainObjectDtoRepository, 7000064);

            var revIndexList = domainObjectDtoRepository.AllInstancesSansSubclasses("ReversalIndex");

            foreach (var revIndexDto in revIndexList)
            {
                var dirty = false;
                // grab ws name(s) from each Reversal Index
                var wsCodeNameDict = new Dictionary <string, string>();
                GetWsNamesFromReversalIndex(revIndexDto, wsCodeNameDict);

                // Find PartsOfSpeech possibility list
                string possListGuid;
                if (!GetGuidForPosListSafely(revIndexDto, out possListGuid))
                {
                    continue;                     // Can't find the PartsOfSpeech list without a guid!
                }
                var posListDto = domainObjectDtoRepository.GetDTO(possListGuid);
                var listElt    = XElement.Parse(posListDto.Xml);

                // Check for the right Depth, ItemClsid and IsSorted values
                var depthElt = listElt.Element(DepthProp);
                if (depthElt != null)
                {
                    depthElt.Remove();                     // Don't want the old one, it was wrong!
                }
                // Replace with a new Property
                var sbDepth = new StringBuilder();
                sbDepth.Append(OpenCloseTagWithValAttr(DepthProp, "127"));
                depthElt = XElement.Parse(sbDepth.ToString());
                listElt.Add(depthElt);
                var clsIdElt = listElt.Element(ClsProp);
                if (clsIdElt == null)                 // Don't replace an existing value
                {
                    // Create the new property
                    var sb = new StringBuilder();
                    sb.Append(OpenCloseTagWithValAttr(ClsProp, Convert.ToString(PosClsId)));
                    clsIdElt = XElement.Parse(sb.ToString());
                    listElt.Add(clsIdElt);
                    dirty = true;
                }
                var sortedElt = listElt.Element(SortProp);
                if (sortedElt == null)
                {
                    var sb = new StringBuilder();
                    sb.Append(OpenCloseTagWithValAttr(SortProp, Truth));
                    sortedElt = XElement.Parse(sb.ToString());
                    listElt.Add(sortedElt);
                    dirty = true;
                }
                if (sortedElt.Attribute("val").Value != Truth)
                {
                    sortedElt.SetAttributeValue("val", Truth);
                    dirty = true;
                }

                // If Name exists skip it, otherwise put a valid name in for each ws that RI Name had.
                var nameElt = listElt.Element(Name);
                if (nameElt == null || nameElt.Element(Auni) == null)
                {
                    if (nameElt != null)
                    {
                        nameElt.Remove();                         // Just in case we end up with an empty name element
                    }
                    var sb = new StringBuilder();
                    sb.Append(OpenTag(Name));
                    foreach (var kvp in wsCodeNameDict)
                    {
                        var wsCode = kvp.Key;
                        var wsName = kvp.Value;
                        sb.AppendFormat(OpenTagWithWsAttr(Auni, wsCode));
                        sb.AppendFormat(Strings.ksReversalIndexPOSListName, wsName);
                        sb.Append(EndTag(Auni));
                    }
                    sb.Append(EndTag(Name));
                    nameElt = XElement.Parse(sb.ToString());
                    listElt.Add(nameElt);
                    dirty = true;
                }
                if (dirty)
                {
                    DataMigrationServices.UpdateDTO(domainObjectDtoRepository, posListDto, listElt.ToString());
                }
            }

            DataMigrationServices.IncrementVersionNumber(domainObjectDtoRepository);
        }
		private static IEnumerable<XElement> ConvertCCAsAndAddCCRObjSurElements(
			IDomainObjectDTORepository dtoRepos,
			IDictionary<string, SortedList<int, byte[]>> paraToOldSegments,
			ICollection<KeyValuePair<byte[], XElement>> halfBakedCcwgItems,
			IDictionary<string, byte[]> oldCCAs,
			IDictionary<Guid, Guid> ccaGuidMap,
			List<string> objsurElementGuids,
			string owningCCRGuid)
		{
			// 'retval' will be put into the new CCR of the caller as owning objsur elements.
			var retval = new List<XElement>(objsurElementGuids.Count());

			// Decide which class to convert the old CCA to:
			//	1. CmBaseAnnotations -> ConstChartTag
			//	2. CmIndirectAnnotation
			//		A. 1 (or more) CCRs in AppliesTo-> ConstChartClauseMarker
			//		B. 1 (only) CCA in AppliesTo -> ConstChartMovedTextMarker
			//		C. null AppliesTo -> ConstChartWordGroup
			//		D. 1 (or more) twfics (pfics?) -> ConstChartWordGroup
			const string kChangeMe = "CHANGEME";
			foreach (var oldCCAGuid in objsurElementGuids)
			{
				var guidOldCCA = new Guid(oldCCAGuid);
				// Earlier 'SortOutMultipleXficBackRefs()' may have left a dangling reference.
				// If so, skip it.
				//XElement oldAnnElement;
				byte[] oldAnnElement;
				if (!oldCCAs.TryGetValue(oldCCAGuid, out oldAnnElement))
					continue;
				//var oldAnnElement = oldCCAs[oldCCAGuid];
				// Leave it in, so we can get at its XElement, whenever needed.
				//oldCCAs.Remove(oldCCAGuid);
				var guidNew = ccaGuidMap[guidOldCCA];
				var newGuid = guidNew.ToString().ToLowerInvariant();
				var newClassName = kChangeMe;
				// Collect up the inner class-level elements.
				var cmAnnotationBounds = new ElementBounds(oldAnnElement, s_tagsCmAnnotation);
				if (!cmAnnotationBounds.IsValid)
					continue;
				// Fix FWR-2139 crash migrating because of missing InstanceOf
				// Skip chart annotation with no column reference.
				var guidInstanceOf = GetInstanceOfGuid(oldAnnElement);
				if (String.IsNullOrEmpty(guidInstanceOf))
					continue;
				var mergesAfterElement = new XElement("MergesAfter", new XAttribute("val", "False"));
				var mergesBeforeElement = new XElement("MergesBefore", new XAttribute("val", "False"));
				// May be null.
				var compDetailsBounds = new ElementBounds(oldAnnElement, s_tagsCompDetails,
					cmAnnotationBounds.BeginTagOffset, cmAnnotationBounds.EndTagOffset);
				if (compDetailsBounds.IsValid)
				{
					var uniBounds = new ElementBounds(oldAnnElement, s_tagsUni,
						compDetailsBounds.BeginTagOffset, compDetailsBounds.EndTagOffset);
					if (uniBounds.IsValid)
					{
						// See if some optional stuff in 'oldCompDetailsElement' will change MergesAfter or MergesBefore.
						var mergeAfter = GetAttributeValue(oldAnnElement, s_mergeAfterAttr,
							uniBounds.BeginTagOffset, uniBounds.EndTagOffset);
						if (mergeAfter == "true")
							mergesAfterElement.Attribute("val").Value = "True";
						var mergeBefore = GetAttributeValue(oldAnnElement, s_mergeBeforeAttr,
							uniBounds.BeginTagOffset, uniBounds.EndTagOffset);
						if (mergeBefore == "true")
							mergesBeforeElement.Attribute("val").Value = "True";
					}
				}
				// Reset the Name and add other elements really soon now,
				// depending on which subclass of ConstituentChartCellPart is used.
				var newSpecificClassElement = new XElement(newClassName);
				var newClassAttr = new XAttribute("class", newClassName);
				var newCCAElement = new XElement("rt",
					newClassAttr,
					new XAttribute("guid", newGuid),
					new XAttribute("ownerguid", owningCCRGuid),
					new XElement("CmObject"),
					new XElement("ConstituentChartCellPart",
						new XElement("Column",
							new XElement("objsur",
								new XAttribute("t", "r"),
								new XAttribute("guid", guidInstanceOf))),
						mergesAfterElement,
						mergesBeforeElement),
					newSpecificClassElement);

				var classValue = GetClassValue(oldAnnElement);
				switch (classValue)
				{
					default:
						throw new InvalidOperationException("Unrecognized annotation class used as CCA.");
					case "CmBaseAnnotation":
						// #1.
						newClassName = "ConstChartTag";
						newSpecificClassElement.Name = newClassName;
						newClassAttr.Value = newClassName;
						// Tag is atomic ref.
						var guidBeginObject = GetBeginObjectGuid(oldAnnElement);
						if (!String.IsNullOrEmpty(guidBeginObject))
						{
							newSpecificClassElement.Add(
								new XElement("Tag",
									new XElement("objsur",
										new XAttribute("t", "r"),
										new XAttribute("guid", guidBeginObject))));
						}
						break;
					case "CmIndirectAnnotation":
						// #2.
						// Get the optional 'AppliesTo' element.
						var refsFromAppliesTo = GetAppliesToObjsurGuids(oldAnnElement);
						if (refsFromAppliesTo == null || refsFromAppliesTo.Count == 0)
						{
							// 2.C
							newClassName = "ConstChartWordGroup";
							newSpecificClassElement.Name = newClassName;
							newClassAttr.Value = newClassName;
							// BeginSegment & EndSegment are to be null, so leave them out altogether.
							// BeginAnalysisIndex & EndAnalysisIndex are both -1.
							// Note: This is actually wrong; this should be a ConstChartTag with no Tag
							//    But it gets fixed in DM7000013.
							newSpecificClassElement.Add(new XElement("BeginAnalysisIndex", new XAttribute("val", "-1")));
							newSpecificClassElement.Add(new XElement("EndAnalysisIndex", new XAttribute("val", "-1")));
						}
						else
						{
							// Get the class of the first (or only) objsur.
							var currentRefGuid = refsFromAppliesTo[0];
							var currentInnerTarget = oldCCAs[refsFromAppliesTo[0]];
							switch (GetAnnotationTypeGuid(currentInnerTarget))
							{
								default:
									throw new InvalidOperationException("Unrecognized annotation type for CCA.");
								case DataMigrationServices.kConstituentChartRowAnnDefnGuid:
									// One, or more, CCRs.
									// 2.A
									newClassName = "ConstChartClauseMarker";
									newSpecificClassElement.Name = newClassName;
									newClassAttr.Value = newClassName;
									var dependentClausesElement = new XElement("DependentClauses");
									newSpecificClassElement.Add(dependentClausesElement);
									foreach (var guid in refsFromAppliesTo)
									{
										// DependentClauses is ref. seq. prop.
										dependentClausesElement.Add(
											DataMigrationServices.CreateReferenceObjSurElement(
												ccaGuidMap[new Guid(guid)].ToString().ToLowerInvariant()));
									}
									break;
								case DataMigrationServices.kConstituentChartAnnotationAnnDefnGuid:
									// Single CCA.
									// 2.B
									newClassName = "ConstChartMovedTextMarker";
									newSpecificClassElement.Name = newClassName;
									newClassAttr.Value = newClassName;
									// WordGroup - Get new guid from cca guid map using old CCA guid.
									newSpecificClassElement.Add(new XElement("WordGroup",
										DataMigrationServices.CreateReferenceObjSurElement(ccaGuidMap[new Guid(currentRefGuid)].ToString().ToLowerInvariant())));
									// Preposed - Boolean.
									// The data migration for the Preposed boolean is simple.
									// If the old Marker's Comment property contains a string "<<" then it's true,
									// false otherwise.
									newSpecificClassElement.Add(new XElement("Preposed",
										new XAttribute("val",
											GetPreposedBooleanFromComment(oldAnnElement,
												cmAnnotationBounds.BeginTagOffset, cmAnnotationBounds.EndTagOffset))));
									break;
								case DataMigrationServices.kPficAnnDefnGuid: // Fall through.
								case DataMigrationServices.kTwficAnnDefnGuid:
									// One, or more, twfics/pfics
									// These all go into halfBakedCcwgItems,
									// and will be finished when Segments and xfics are finished.

									// NB: While there may be multiple xfics,
									// only the first and last are stored in the two indices.
									var firstXficGuid = currentRefGuid;
									var lastXficGuid = refsFromAppliesTo[refsFromAppliesTo.Count - 1];
									var firstXficInnerAnnElement = XElement.Parse(dtoRepos.GetDTO(firstXficGuid).Xml).Element("CmBaseAnnotation");
									// Gotta make sure the xfics and segments are in the same paragraph.
									var paraGuid = GetGuid(firstXficInnerAnnElement.Element("BeginObject").Element("objsur"));
									var beginOffsetElement = firstXficInnerAnnElement.Element("BeginOffset");
									var firstXfixBeginOffset = beginOffsetElement == null ? 0 : int.Parse(beginOffsetElement.Attribute("val").Value);
									var newSegmentGuid = kChangeMe;

									try
									{
										foreach (var kvp in paraToOldSegments[paraGuid].TakeWhile(kvp => kvp.Key <= firstXfixBeginOffset))
										{
											// Found the right segment, so get its new segment guid.
											newSegmentGuid = ccaGuidMap[new Guid(GetGuid(kvp.Value))].ToString().ToLowerInvariant();
										}
									}
									catch (KeyNotFoundException)
									{
										// Upon finding an orphaned chart cell with an invalid paragraph, skip it.
										continue;
									}
									if (newSegmentGuid == kChangeMe)
									{
										// We might have some segments (better check), but there are xfics that aren't
										// covered by a segment, so try to recover the broken data, as much as possible.
										newSegmentGuid = AddExtraInitialSegment(paraGuid, ccaGuidMap, paraToOldSegments);
									}

									halfBakedCcwgItems.Add(new KeyValuePair<byte[], XElement>(oldAnnElement, newCCAElement));
									newClassName = "ConstChartWordGroup";
									newSpecificClassElement.Name = newClassName;
									newClassAttr.Value = newClassName;
									newSpecificClassElement.Add(new XElement("BeginSegment",
										DataMigrationServices.CreateReferenceObjSurElement(newSegmentGuid)));
									newSpecificClassElement.Add(new XElement("EndSegment",
										DataMigrationServices.CreateReferenceObjSurElement(newSegmentGuid)));
									// For now, just store the guid of the first xfic.
									// It's the wrong data type, but xml won't care,
									// and, they will get changed later on.
									newSpecificClassElement.Add(new XElement("BeginAnalysisIndex",
										new XAttribute("val", firstXficGuid)));
									// For now, just store the guid of the last xfic.
									// It's the wrong data type, but xml won't care,
									// and, they will get changed later on.
									newSpecificClassElement.Add(new XElement("EndAnalysisIndex",
										new XAttribute("val", lastXficGuid)));
									break;
							}
						}
						break;
				}

				// Create new owning objSur Element.
				retval.Add(DataMigrationServices.CreateOwningObjSurElement(newGuid));

				// Add newly converted CCA to repos.
				dtoRepos.Add(new DomainObjectDTO(newGuid, newClassName, newCCAElement.ToString()));
			}

			return retval;
		}
		/// <summary>
		/// Add a few items to the Notebook Record Type list, and rearrange the list a bit.  The original
		/// list should look something like:
		///		Conversation
		///		Interview
		///			Structured
		///			Unstructured
		///		Literature Summary
		///		Observation
		///			Performance
		///		Analysis
		///	After the migration, the list should look something like:
		///		Event
		///			Observation
		///			Conversation
		///			Interview
		///				Structured
		///				Unstructured
		///			Performance
		///		Literature Summary
		///		Analysis
		///		Methodology
		///		Weather
		/// </summary>
		/// <remarks>
		/// This implements FWR-643.  Note that users can edit this list, so any of the expected
		/// items could have been deleted or moved around in the list.  :-(
		/// </remarks>
		public void PerformMigration(IDomainObjectDTORepository repoDTO)
		{
			DataMigrationServices.CheckVersionNumber(repoDTO, 7000015);

			DomainObjectDTO dtoList = repoDTO.GetDTO(ksguidRecTypesList);
			XElement xeList = XElement.Parse(dtoList.Xml);
			XElement xeListPossibilities = xeList.XPathSelectElement("Possibilities");
			if (xeListPossibilities == null)
			{
				xeListPossibilities = new XElement("Possibilities");
				xeList.Add(xeListPossibilities);
			}
			// The user can edit the list, so these might possibly have been deleted (or moved).  :-(
			DomainObjectDTO dtoObservation = GetDTOIfItExists(repoDTO, ksguidObservation);
			DomainObjectDTO dtoConversation = GetDTOIfItExists(repoDTO, ksguidConversation);
			DomainObjectDTO dtoInterview = GetDTOIfItExists(repoDTO, ksguidInterview);
			DomainObjectDTO dtoPerformance = GetDTOIfItExists(repoDTO, ksguidPerformance);

			// Create the new Event, Methodology, and Weather record types.
			var nowStr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");

			StringBuilder sb = new StringBuilder();
			sb.AppendFormat("<rt class=\"CmPossibility\" guid=\"{0}\" ownerguid=\"{1}\">",
				ksguidEvent, ksguidRecTypesList);
			sb.Append("<Abbreviation><AUni ws=\"en\">Evnt</AUni></Abbreviation>");
			sb.Append("<Name><AUni ws=\"en\">Event</AUni></Name>");
			sb.AppendFormat("<DateCreated val=\"{0}\"/>", nowStr);
			sb.AppendFormat("<DateModified val=\"{0}\"/>", nowStr);
			sb.Append("</rt>");
			XElement xeEvent = XElement.Parse(sb.ToString());
			var dtoEvent = new DomainObjectDTO(ksguidEvent, "CmPossibility", xeEvent.ToString());
			repoDTO.Add(dtoEvent);
			xeListPossibilities.AddFirst(DataMigrationServices.CreateOwningObjSurElement(ksguidEvent));

			sb = new StringBuilder();
			sb.AppendFormat("<rt class=\"CmPossibility\" guid=\"{0}\" ownerguid=\"{1}\">",
				ksguidMethodology, ksguidRecTypesList);
			sb.Append("<Abbreviation><AUni ws=\"en\">Method</AUni></Abbreviation>");
			sb.Append("<Name><AUni ws=\"en\">Methodology</AUni></Name>");
			sb.AppendFormat("<DateCreated val=\"{0}\"/>", nowStr);
			sb.AppendFormat("<DateModified val=\"{0}\"/>", nowStr);
			sb.Append("</rt>");
			var dtoMethod = new DomainObjectDTO(ksguidMethodology, "CmPossibility", sb.ToString());
			repoDTO.Add(dtoMethod);
			xeListPossibilities.LastNode.AddAfterSelf(DataMigrationServices.CreateOwningObjSurElement(ksguidMethodology));

			sb = new StringBuilder();
			sb.AppendFormat("<rt class=\"CmPossibility\" guid=\"{0}\" ownerguid=\"{1}\">",
				ksguidWeather, ksguidRecTypesList);
			sb.Append("<Abbreviation><AUni ws=\"en\">Wthr</AUni></Abbreviation>");
			sb.Append("<Name><AUni ws=\"en\">Weather</AUni></Name>");
			sb.AppendFormat("<DateCreated val=\"{0}\"/>", nowStr);
			sb.AppendFormat("<DateModified val=\"{0}\"/>", nowStr);
			sb.Append("</rt>");
			var dtoWeather = new DomainObjectDTO(ksguidWeather, "CmPossibility", sb.ToString());
			repoDTO.Add(dtoWeather);
			xeListPossibilities.LastNode.AddAfterSelf(DataMigrationServices.CreateOwningObjSurElement(ksguidWeather));

			DataMigrationServices.UpdateDTO(repoDTO, dtoList, xeList.ToString());

			// Change the ownership links for the moved items.
			if (dtoObservation != null)
				ChangeOwner(repoDTO, dtoObservation, ksguidEvent, "SubPossibilities");
			if (dtoConversation != null)
				ChangeOwner(repoDTO, dtoConversation, ksguidEvent, "SubPossibilities");
			if (dtoInterview != null)
				ChangeOwner(repoDTO, dtoInterview, ksguidEvent, "SubPossibilities");
			if (dtoPerformance != null)
				ChangeOwner(repoDTO, dtoPerformance, ksguidEvent, "SubPossibilities");

			DataMigrationServices.IncrementVersionNumber(repoDTO);
		}