Class to be used as the Data Transfer Object (DTO) between BEP-land and Data Migration-land (DM-land). (DTOs move data from point A to point B, but have no behavior.) An instance of DomainObjectDTO will represent one ICmObject of some class, but will be able to 'live' in an older model version and a newer model version during a data migration, where a real ICmObject could not. Instances of this object will be available to DM-land via a special Repository.
Exemple #1
0
        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 #2
0
        /// <summary>
        /// Creates a CmPossibility with all the basic properties filled in for the xml (necessary for S/R) and adds it to the dto
        /// </summary>
        public static DomainObjectDTO CreatePossibility(IDomainObjectDTORepository repoDto, string listGuid, string possibilityGuid, string name,
                                                        string abbr, DateTime createTime, string className = "CmPossibility")
        {
            var sb = new StringBuilder();

            sb.AppendFormat("<rt class=\"{0}\" guid=\"{1}\" ownerguid=\"{2}\">", className, possibilityGuid, listGuid);
            sb.Append("<Abbreviation>");
            sb.AppendFormat("<AUni ws=\"en\">{0}</AUni>", abbr);
            sb.Append("</Abbreviation>");
            sb.Append(string.Format("<DateCreated val=\"{0:yyyy-MM-dd HH:mm:ss.fff}\" />", createTime));
            sb.Append(string.Format("<DateModified val=\"{0:yyyy-MM-dd HH:mm:ss.fff}\" />", createTime));
            sb.Append("<BackColor val=\"-1073741824\" />");
            sb.Append("<ForeColor val=\"-1073741824\" />");
            sb.Append("<IsProtected val=\"True\" />");
            sb.Append("<Hidden val=\"False\" />");
            sb.Append("<Name>");
            sb.AppendFormat("<AUni ws=\"en\">{0}</AUni>", name);
            sb.Append("</Name>");
            sb.Append("<SortSpec val=\"-1073741824\" />");
            sb.Append("<UnderColor val=\"-1073741824\" />");
            sb.Append("<UnderStyle val=\"-1073741824\" />");
            sb.Append("</rt>");
            var dtoCmPossibility = new DomainObjectDTO(possibilityGuid, className, sb.ToString());

            repoDto.Add(dtoCmPossibility);
            return(dtoCmPossibility);
        }
Exemple #3
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);
        }
		public void PerformMigration(IDomainObjectDTORepository domainObjectDtoRepository)
		{
			DataMigrationServices.CheckVersionNumber(domainObjectDtoRepository, 7000050);

			var newGuidValue = Guid.NewGuid().ToString().ToLowerInvariant();
			const string className = "LangProject";
			var lpDto = domainObjectDtoRepository.AllInstancesSansSubclasses(className).First();
			var ownedDtos = domainObjectDtoRepository.GetDirectlyOwnedDTOs(lpDto.Guid).ToList();
			var data = lpDto.Xml;
			domainObjectDtoRepository.Remove(lpDto); // It is pretty hard to change an immutable Guid identifier in BEP-land, so nuke it, and make a new one.

			var lpElement = XElement.Parse(data);
			lpElement.Attribute("guid").Value = newGuidValue;
			var newLpDto = new DomainObjectDTO(newGuidValue, className, lpElement.ToString());
			domainObjectDtoRepository.Add(newLpDto);

			// Change ownerguid attr for each owned item to new guid.
			foreach (var ownedDto in ownedDtos)
			{
				var ownedElement = XElement.Parse(ownedDto.Xml);
				ownedElement.Attribute("ownerguid").Value = newGuidValue;
				ownedDto.Xml = ownedElement.ToString();
				domainObjectDtoRepository.Update(ownedDto);
			}

			DataMigrationServices.IncrementVersionNumber(domainObjectDtoRepository);
		}
        private void AddToClassList(DomainObjectDTO dto)
        {
            var    className = dto.Classname;
            string superclassName;

            if (!m_classAndSuperClass.TryGetValue(className, out superclassName))
            {
                // Can't determine old superclass, without going through the DTO's xml.
                m_classAndSuperClass.Add(className, null);
                // Discovering old direct subclasses may not be possible.
                m_classesAndTheirDirectSubclasses.Add(className, new HashSet <string>());
            }
            if (superclassName == null)
            {
                // Unknown class, so must be obsolete.
                m_oldTimers.Add(dto);
            }
            HashSet <DomainObjectDTO> instances;

            if (!m_dtosByClass.TryGetValue(className, out instances))
            {
                instances = new HashSet <DomainObjectDTO>();
                m_dtosByClass.Add(className, instances);
            }
            instances.Add(dto);
        }
        public void PerformMigration(IDomainObjectDTORepository domainObjectDtoRepository)
        {
            DataMigrationServices.CheckVersionNumber(domainObjectDtoRepository, 7000050);

            var          newGuidValue = Guid.NewGuid().ToString().ToLowerInvariant();
            const string className    = "LangProject";
            var          lpDto        = domainObjectDtoRepository.AllInstancesSansSubclasses(className).First();
            var          ownedDtos    = domainObjectDtoRepository.GetDirectlyOwnedDTOs(lpDto.Guid).ToList();
            var          data         = lpDto.Xml;

            domainObjectDtoRepository.Remove(lpDto);             // It is pretty hard to change an immutable Guid identifier in BEP-land, so nuke it, and make a new one.

            var lpElement = XElement.Parse(data);

            lpElement.Attribute("guid").Value = newGuidValue;
            var newLpDto = new DomainObjectDTO(newGuidValue, className, lpElement.ToString());

            domainObjectDtoRepository.Add(newLpDto);

            // Change ownerguid attr for each owned item to new guid.
            foreach (var ownedDto in ownedDtos)
            {
                var ownedElement = XElement.Parse(ownedDto.Xml);
                ownedElement.Attribute("ownerguid").Value = newGuidValue;
                ownedDto.Xml = ownedElement.ToString();
                domainObjectDtoRepository.Update(ownedDto);
            }

            DataMigrationServices.IncrementVersionNumber(domainObjectDtoRepository);
        }
Exemple #7
0
 /// <summary>
 /// Add to weatherItems the guids of all the things owned directly or indirectly by dtoRoot.
 /// Does not include the root itself.
 /// </summary>
 private void CollectItems(IDomainObjectDTORepository repoDTO, DomainObjectDTO dtoRoot, HashSet <string> guidCollector)
 {
     foreach (var dto in repoDTO.GetDirectlyOwnedDTOs(dtoRoot.Guid))
     {
         guidCollector.Add(dto.Guid);
         CollectItems(repoDTO, dto, guidCollector);
     }
 }
Exemple #8
0
        /// <summary>
        /// The weather list is used, so convert it to a custom (unowned) list, create a new
        /// custom field for RnGenericRec elements, and convert any Weather elements to that
        /// new custom field.
        /// </summary>
        private void ConvertWeatherToCustomListAndField(IDomainObjectDTORepository repoDTO)
        {
            // Change the Weather list to being unowned.
            DomainObjectDTO dtoLP = null;

            foreach (var dto in repoDTO.AllInstancesWithSubclasses("LangProject"))
            {
                dtoLP = dto;
                break;
            }
            string sWeatherListGuid = RemoveWeatherConditionsElement(dtoLP).ToLowerInvariant();

            repoDTO.Update(dtoLP);
            DomainObjectDTO dtoWeatherList = null;

            foreach (var dto in repoDTO.AllInstancesWithSubclasses("CmPossibilityList"))
            {
                if (dto.Guid.ToLowerInvariant() == sWeatherListGuid)
                {
                    dtoWeatherList = dto;
                    break;
                }
            }
            dtoWeatherList.Xml = RemoveOwnerGuid(dtoWeatherList.Xml);
            repoDTO.Update(dtoWeatherList);

            // Create the custom field.
            string fieldName = "Weather";

            while (repoDTO.IsFieldNameUsed("RnGenericRec", fieldName))
            {
                fieldName = fieldName + "A";
            }
            repoDTO.CreateCustomField("RnGenericRec", fieldName, SIL.CoreImpl.CellarPropertyType.ReferenceCollection,
                                      CmPossibilityTags.kClassId, "originally a standard part of Data Notebook records",
                                      WritingSystemServices.kwsAnals, new Guid(sWeatherListGuid));

            string customStart = String.Format("<Custom name=\"{0}\">", fieldName);

            // Remove any empty Weather elements in the RnGenericRec objects, and convert
            // nonempty ones to custom elements.
            foreach (var dto in repoDTO.AllInstancesWithSubclasses("RnGenericRec"))
            {
                string sXml = dto.Xml;
                int    idx  = sXml.IndexOf("<Weather");
                if (idx > 0)
                {
                    string sXmlT = RemoveEmptyWeather(sXml, idx);
                    if (sXmlT == sXml)
                    {
                        sXmlT = sXml.Replace("<Weather>", customStart);
                        sXmlT = sXmlT.Replace("</Weather>", "</Custom>");
                    }
                    dto.Xml = sXmlT;
                    repoDTO.Update(dto);
                }
            }
        }
Exemple #9
0
 private void GatherDeadObjects(IDomainObjectDTORepository repoDTO, DomainObjectDTO dtoDead,
                                List <DomainObjectDTO> rgdtoDead)
 {
     rgdtoDead.Add(dtoDead);
     foreach (var dto in repoDTO.GetDirectlyOwnedDTOs(dtoDead.Guid))
     {
         GatherDeadObjects(repoDTO, dto, rgdtoDead);
     }
 }
Exemple #10
0
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Removes the specified field.
        /// </summary>
        /// <param name="dto">The domain transfer object that has a field that may need to be deleted.</param>
        /// <param name="objElement">Name of the object containing fieldToDelete.</param>
        /// <param name="fieldToDelete">The name of the field to delete.</param>
        /// ------------------------------------------------------------------------------------
        private void RemoveField(DomainObjectDTO dto, XElement objElement, string fieldToDelete)
        {
            XElement rmElement = objElement.Element(fieldToDelete);

            if (rmElement != null)
            {
                rmElement.Remove();
            }
        }
        private void RemoveFromClassList(DomainObjectDTO obj, string oldClassName)
        {
            HashSet <DomainObjectDTO> instances;

            if (m_dtosByClass.TryGetValue(oldClassName, out instances))
            {
                instances.Remove(obj);
            }
        }
		internal static void CheckDtoRemoved(IDomainObjectDTORepository dtoRepos, DomainObjectDTO goner)
		{
			DomainObjectDTO dto;
			if (dtoRepos.TryGetValue(goner.Guid, out dto))
			{
				Assert.Fail("Still has deleted (or zombie) DTO.");
			}
			Assert.IsTrue(((DomainObjectDtoRepository)dtoRepos).Goners.Contains(goner));
		}
		public void DataMigration7000009Test()
		{
			var dtos = new HashSet<DomainObjectDTO>();
			var sb = new StringBuilder();
			// 1. Add barebones LP.
			sb.Append("<rt class=\"LangProject\" guid=\"9719A466-2240-4DEA-9722-9FE0746A30A6\">");
			sb.Append("<LangProject>");
			sb.Append("<Texts>");
			var lpTextsGuids = new StTextAndParaInfo("9719A466-2240-4DEA-9722-9FE0746A30A6", "Normal");
			sb.Append("<objsur guid=\"" + lpTextsGuids.textGuid + "\" t=\"o\" />");
			sb.Append("</Texts>");
			sb.Append("<TranslatedScripture>");
			sb.Append("<objsur guid=\"2c5c1f5f-1f08-41d7-99fe-23893ee4ceef\" t=\"o\" />");
			sb.Append("</TranslatedScripture>");
			sb.Append("</LangProject>");
			sb.Append("</rt>");
			var expectedLp = sb.ToString();
			var lpDto = new DomainObjectDTO("9719A466-2240-4DEA-9722-9FE0746A30A6",
											"LangProject",
											expectedLp);
			dtos.Add(lpDto);

			// 2. Add Scripture
			sb = new StringBuilder();
			sb.Append(
				"<rt class=\"Scripture\" guid=\"2c5c1f5f-1f08-41d7-99fe-23893ee4ceef\" ownerguid=\"9719A466-2240-4DEA-9722-9FE0746A30A6\"");
			int index = sb.Length;
			sb.Append(">");
			sb.Append("<Scripture>");
			sb.Append("<Books>");
			sb.Append("<objsur guid=\"f213db11-7007-4a2f-9b94-06d6c96014ca\" t=\"o\" />");
			sb.Append("</Books>");
			sb.Append("</Scripture>");
			sb.Append("</rt>");
			string expected = sb.ToString();
			sb.Insert(index, " owningflid=\"6001040\" owningord=\"0\"");

			var scrDto = new DomainObjectDTO("2c5c1f5f-1f08-41d7-99fe-23893ee4ceef",
											 "Scripture",
											 sb.ToString());
			dtos.Add(scrDto);
			// Set up mock MDC.
			var mockMDC = new MockMDCForDataMigration();
			mockMDC.AddClass(1, "CmObject", null, new List<string> { "LangProject", "Scripture" });
			mockMDC.AddClass(2, "LangProject", "CmObject", new List<string>());
			mockMDC.AddClass(4, "Scripture", "CmObject", new List<string>());
			IDomainObjectDTORepository dtoRepos = new DomainObjectDtoRepository(7000008, dtos, mockMDC, null, FwDirectoryFinder.FdoDirectories);

			m_dataMigrationManager.PerformMigration(dtoRepos, 7000009, new DummyProgressDlg());

			Assert.AreEqual(expected, scrDto.Xml);
			Assert.AreEqual(expectedLp, lpDto.Xml);

			Assert.AreEqual(7000009, dtoRepos.CurrentModelVersion, "Wrong updated version.");

		}
Exemple #14
0
        private void RemoveUnwantedOverlays(IDomainObjectDTORepository repoDTO, List <DomainObjectDTO> collectOverlaysToRemove)
        {
            DomainObjectDTO dtoLP = GetDtoLangProj(repoDTO);

            foreach (var dto in collectOverlaysToRemove)
            {
                RemoveOverlayElement(dtoLP, dto.Guid);
                repoDTO.Remove(dto);
            }
        }
		/// <summary>
		/// Rest the xml in the DTO and register the DTO as udated with the repository.
		/// Use this overload only if the class name is NOT changing.
		/// </summary>
		/// <remarks>
		/// There is no validation of the xml, other than making sure it is not null,
		/// or an emty string.
		/// </remarks>
		internal static void UpdateDTO(IDomainObjectDTORepository dtoRepos,
			DomainObjectDTO dirtball, string newXmlValue)
		{
			if (dtoRepos == null) throw new ArgumentNullException("dtoRepos");
			if (dirtball == null) throw new ArgumentNullException("dirtball");
			if (String.IsNullOrEmpty(newXmlValue)) throw new ArgumentNullException("newXmlValue");

			dirtball.Xml = newXmlValue;
			dtoRepos.Update(dirtball);
		}
		/// <summary>
		/// Rest the xml in the DTO and register the DTO as udated with the repository.
		/// Use this overload only if the class name is NOT changing.
		/// </summary>
		/// <remarks>
		/// There is no validation of the xml, other than making sure it is not null,
		/// or an emty string.
		/// </remarks>
		internal static void UpdateDTO(IDomainObjectDTORepository dtoRepos,
			DomainObjectDTO dirtball, byte[] newXmlBytes)
		{
			if (dtoRepos == null) throw new ArgumentNullException("dtoRepos");
			if (dirtball == null) throw new ArgumentNullException("dirtball");
			if (newXmlBytes == null || newXmlBytes.Length == 0) throw new ArgumentNullException("newXmlBytes");

			dirtball.XmlBytes = newXmlBytes;
			dtoRepos.Update(dirtball);
		}
		void ChangeClassOfOwnerAndChildren(IDomainObjectDTORepository dtoRepo, DomainObjectDTO dtoToChange, string oldClassname, string newClassname)
		{
			// bail out if we've already changed the class name (assume we've already changed its children too).
			if (!TryChangeOwnerClass(dtoRepo, dtoToChange, oldClassname, newClassname))
				return;
			foreach (var dtoChild in dtoRepo.GetDirectlyOwnedDTOs(dtoToChange.Guid))
			{
				ChangeClassOfOwnerAndChildren(dtoRepo, dtoChild, oldClassname, newClassname);
			}
		}
Exemple #18
0
        private DomainObjectDTO GetDtoLangProj(IDomainObjectDTORepository repoDTO)
        {
            DomainObjectDTO dtoLP = null;

            foreach (var dto in repoDTO.AllInstancesWithSubclasses("LangProject"))
            {
                dtoLP = dto;
                break;
            }
            return(dtoLP);
        }
		public void DataMigration7000056Test()
		{
			var dtos = DataMigrationTestServices.ParseProjectFile("DataMigration7000056.xml");
			// Set up mock MDC.
			var mockMDC = new MockMDCForDataMigration();
			IDomainObjectDTORepository dtoRepos = new DomainObjectDtoRepository(7000055, dtos, mockMDC, null, FwDirectoryFinder.FdoDirectories);

			m_dataMigrationManager.PerformMigration(dtoRepos, 7000056, new DummyProgressDlg());
			Assert.AreEqual(7000056, dtoRepos.CurrentModelVersion, "Wrong updated version.");

			// check that PhPhonData has the PhonRuleFeats possibility list
			{
				var dtosList = dtoRepos.AllInstancesSansSubclasses("PhPhonData");
				DomainObjectDTO dtoPhPhonDataTest = dtosList.First();
				CheckPhPhonData(dtoPhPhonDataTest, dtoRepos);
			}

			// In the extremely unlikely event that there is no PhPhonData yet, check that we add it
			{
				dtos = new HashSet<DomainObjectDTO>();

				var sb = new StringBuilder();
				// Add WfiMorphBundle that already has a form.
				const string sGuid_wmbLangProj = "00b35f9f-86ce-4f07-bde7-b65c28503641";

				sb.AppendFormat("<rt class=\"LangProj\" guid=\"{0}\">", sGuid_wmbLangProj);
				sb.Append("</rt>");
				var dtoLangProj = new DomainObjectDTO(sGuid_wmbLangProj, "LangProj", sb.ToString());
				dtos.Add(dtoLangProj);
				sb.Length = 0;

				mockMDC = new MockMDCForDataMigration();
				dtoRepos = new DomainObjectDtoRepository(7000055, dtos, mockMDC, null, FwDirectoryFinder.FdoDirectories);
				m_dataMigrationManager.PerformMigration(dtoRepos, 7000056, new DummyProgressDlg());
				Assert.AreEqual(7000056, dtoRepos.CurrentModelVersion, "Wrong updated version.");

				var dtosList = dtoRepos.AllInstancesSansSubclasses("LangProj");
				DomainObjectDTO dtoLangProjTest = dtosList.First();
				var eltWmbLangProjTest = XElement.Parse(dtoLangProjTest.Xml);
				// get phon rule feats
				var eltPhonologicalDataTest = eltWmbLangProjTest.Element("PhonologicalData");
				Assert.IsNotNull(eltPhonologicalDataTest);
				var eltObjsurTest = eltPhonologicalDataTest.Element("objsur");
				Assert.IsNotNull(eltObjsurTest);
				// get possibility list itself
				var guidPhPhonDataTest = eltObjsurTest.Attribute("guid").Value;
				Assert.IsNotNull(guidPhPhonDataTest);
				DomainObjectDTO dtoPhPhonDataTest;
				dtoRepos.TryGetValue(guidPhPhonDataTest, out dtoPhPhonDataTest);
				Assert.IsNotNull(dtoPhPhonDataTest);
				CheckPhPhonData(dtoPhPhonDataTest, dtoRepos);

			}
		}
Exemple #20
0
        /// <summary>
        /// Does two components of changing the class of a DTO representation of the object:
        /// Fixes the class attribute, and fixes the Classname of the DTO.
        /// Caller should arrange to move it from one list to another, and fix the
        /// embedded elements (see e.g. ChangeToSubClass).
        /// </summary>
        /// <param name="target"></param>
        /// <param name="oldClass"></param>
        /// <param name="newClass"></param>
        private static void ChangeClass(DomainObjectDTO target, string oldClass, string newClass)
        {
            // If there's no unexpected white space we can do this efficiently.
            // This depends (like various other code) on NOT having unexpected white space around the '='.
            byte[] classBytes = Encoding.UTF8.GetBytes("class=\"" + oldClass + "\"");
            int    index      = target.XmlBytes.IndexOfSubArray(classBytes);

            byte[] newClassBytes = Encoding.UTF8.GetBytes("class=\"" + newClass + "\"");
            target.XmlBytes  = target.XmlBytes.ReplaceSubArray(index, classBytes.Length, newClassBytes);
            target.Classname = newClass;
        }
		private void VerifyAnalysis(DomainObjectDTO analysis, string[] evaluations)
		{
			var rtElement = XElement.Parse(analysis.Xml);
			var agentElt = rtElement.Element("WfiAnalysis");
			var evaluationsElt = agentElt.Element("Evaluations");
			Assert.IsNotNull(evaluationsElt);
			Assert.AreEqual(evaluations.Length, evaluationsElt.Elements().Count());
			var wanted = new HashSet<string>(evaluations);
			foreach (var objsur in evaluationsElt.Elements())
				VerifyReference(objsur, wanted);
		}
Exemple #22
0
        private string RemoveWeatherConditionsElement(DomainObjectDTO dtoLP)
        {
            string sLpXml             = dtoLP.Xml;
            int    idx                = sLpXml.IndexOf("<WeatherConditions>");
            int    idxEnd             = sLpXml.IndexOf("</WeatherConditions>");
            int    cch                = (idxEnd + 20) - idx;
            string sWeatherConditions = sLpXml.Substring(idx, cch);

            dtoLP.Xml = sLpXml.Remove(idx, cch);
            return(ExtractFirstGuid(sWeatherConditions, 0, " guid=\""));
        }
Exemple #23
0
        private string GetFilePath(DomainObjectDTO file)
        {
            var fileElement = XElement.Parse(file.Xml);
            var pathElement = fileElement.Element("InternalPath");

            if (pathElement != null)
            {
                pathElement = pathElement.Element("Uni");
            }
            return(pathElement != null ? pathElement.Value : null);
        }
        private static void GetWsNamesFromReversalIndex(DomainObjectDTO revIndexDto, Dictionary <string, string> wsCodeNameDict)
        {
            var wsElt = XElement.Parse(revIndexDto.Xml).Element(Name);
            var existingNameAUniElts = wsElt.Elements(Auni);

            foreach (var aUniElt in existingNameAUniElts)
            {
                var wsCode  = aUniElt.Attribute("ws").Value;
                var wsUiStr = aUniElt.Value;
                wsCodeNameDict.Add(wsCode, wsUiStr);
            }
        }
Exemple #25
0
 void ChangeClassOfOwnerAndChildren(IDomainObjectDTORepository dtoRepo, DomainObjectDTO dtoToChange, string oldClassname, string newClassname)
 {
     // bail out if we've already changed the class name (assume we've already changed its children too).
     if (!TryChangeOwnerClass(dtoRepo, dtoToChange, oldClassname, newClassname))
     {
         return;
     }
     foreach (var dtoChild in dtoRepo.GetDirectlyOwnedDTOs(dtoToChange.Guid))
     {
         ChangeClassOfOwnerAndChildren(dtoRepo, dtoChild, oldClassname, newClassname);
     }
 }
Exemple #26
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);
        }
        /// <summary>
        /// Remove a 'deleted' <see cref="DomainObjectDTO"/> from the repository.
        ///
        /// The deletion of the underlying CmObject object won't happen,
        /// until the entire current migration is finished.
        /// </summary>
        /// <param name="goner">The object being deleted.</param>
        void IDomainObjectDTORepository.Remove(DomainObjectDTO goner)
        {
            if (goner == null)
            {
                throw new ArgumentNullException("goner");
            }

            m_goners.Add(goner);
            m_dtoByGuid.Remove(goner.Guid.ToLower());
            m_dtos.Remove(goner);
            RemoveFromClassList(goner);
        }
		bool TryChangeOwnerClass(IDomainObjectDTORepository dtoRepo, DomainObjectDTO dtoToChange, string oldClassname, string newClassname)
		{
			XElement dtoToChangeElt = XElement.Parse(dtoToChange.Xml);
			if (dtoToChangeElt.Attribute("class").Value != oldClassname)
				return false;
			dtoToChangeElt.Attribute("class").Value = newClassname;
			dtoToChange.Classname = newClassname;
			// next go through all the children of these known system variant types and change all of their children's classes.

			DataMigrationServices.UpdateDTO(dtoRepo, dtoToChange, dtoToChangeElt.ToString(), oldClassname);
			return true;
		}
        /// <summary>
        /// Let the Repository know that <paramref name="dirtball"/> has been modified.
        /// </summary>
        /// <param name="dirtball">The object that was modified.</param>
        /// <remarks>
        /// The underlying CmObject won't be changed, until the end of the current
        /// migration is finished.
        /// </remarks>
        void IDomainObjectDTORepository.Update(DomainObjectDTO dirtball)
        {
            if (dirtball == null)
            {
                throw new ArgumentNullException("dirtball");
            }
            if (!m_dtoByGuid.ContainsKey(dirtball.Guid.ToLower()))
            {
                throw new InvalidOperationException("Can't update DTO that isn't in the system.");
            }

            m_dirtballs.Add(dirtball);
        }
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Get the owner <see cref="DomainObjectDTO"/> for the specified object.
        /// </summary>
        /// <param name="ownedObj">The owned <see cref="DomainObjectDTO"/>.</param>
        /// <returns>
        /// The owner <see cref="DomainObjectDTO"/> for the given <paramref name="ownedObj"/>,
        /// or null, if there is no owner.
        /// </returns>
        /// <exception cref="ArgumentException">
        /// Thrown if the owned object is not in the repository.
        /// </exception>
        /// ------------------------------------------------------------------------------------
        DomainObjectDTO IDomainObjectDTORepository.GetOwningDTO(DomainObjectDTO ownedObj)
        {
            if (ownedObj == null)
            {
                throw new ArgumentNullException("ownedObj");
            }

            var ownIdx = ownedObj.XmlBytes.IndexOfSubArray(OwnerGuid);

            return((ownIdx < 0)
                                ? null
                                : AsInterface.GetDTO(Encoding.UTF8.GetString(ownedObj.XmlBytes.SubArray(ownIdx + 11, 36))));
        }
Exemple #31
0
        private static void UpdateObjSurElement(IDomainObjectDTORepository dtoRepos, DomainObjectDTO dto, string oldGuid, string newGuid)
        {
            var rtElem            = XElement.Parse(dto.Xml);
            var ownObjSurGuidAttr = (from objSurNode in rtElem.Descendants("objsur")
                                     where objSurNode.Attribute("guid").Value.ToLower() == oldGuid.ToLower()
                                     select objSurNode.Attribute("guid")).FirstOrDefault();                                     // Ought not be null, but play it safe.

            if (ownObjSurGuidAttr != null)
            {
                ownObjSurGuidAttr.Value = newGuid;
            }
            UpdateDTO(dtoRepos, dto, rtElem.ToString());
        }
		private static void VerifyObject(DomainObjectDTO dto, IEnumerable<string> oldClassElements, ICollection<string> expectedPropertyElements)
		{
			// Make sure the old class elements are gone.
			var rtElement = XElement.Parse(dto.Xml);
			foreach (var oldClassElement in oldClassElements)
				Assert.IsNull(rtElement.Element(oldClassElement));

			// Make sure the prop elements are child elements of <rt> element.
			var propElements = rtElement.Elements();
			Assert.AreEqual(expectedPropertyElements.Count, propElements.Count(), "Wrong number of property child elements.");
			foreach (var propElement in propElements)
				Assert.IsTrue(expectedPropertyElements.Contains(propElement.Name.LocalName));
		}
        /// <summary>
        /// Add a new <see cref="DomainObjectDTO"/> to the repository.
        /// </summary>
        /// <param name="newby">The new object to add.</param>
        void IDomainObjectDTORepository.Add(DomainObjectDTO newby)
        {
            if (newby == null)
            {
                throw new ArgumentNullException("newby");
            }

            // Will throw an exception, if it is already present,
            // which is just fine.
            m_dtoByGuid.Add(newby.Guid.ToLower(), newby);
            m_dtos.Add(newby);
            AddToClassList(newby);
            m_newbies.Add(newby);
        }
Exemple #34
0
        private void RemoveReferenceFromPictures(IDomainObjectDTORepository repoDto, DomainObjectDTO langProj,
                                                 string guid)
        {
            var langProjElement = XElement.Parse(langProj.Xml);

            foreach (var x in langProjElement.Element("Pictures").Elements())
            {
                if (x.Attribute("guid").Value == guid)
                {
                    x.Remove();
                    break;
                }
            }
            DataMigrationServices.UpdateDTO(repoDto, langProj, langProjElement.ToString());
        }
Exemple #35
0
        bool TryChangeOwnerClass(IDomainObjectDTORepository dtoRepo, DomainObjectDTO dtoToChange, string oldClassname, string newClassname)
        {
            XElement dtoToChangeElt = XElement.Parse(dtoToChange.Xml);

            if (dtoToChangeElt.Attribute("class").Value != oldClassname)
            {
                return(false);
            }
            dtoToChangeElt.Attribute("class").Value = newClassname;
            dtoToChange.Classname = newClassname;
            // next go through all the children of these known system variant types and change all of their children's classes.

            DataMigrationServices.UpdateDTO(dtoRepo, dtoToChange, dtoToChangeElt.ToString(), oldClassname);
            return(true);
        }
Exemple #36
0
        private void MoveFileToFolder(IDomainObjectDTORepository repoDto, DomainObjectDTO folder, DomainObjectDTO fileToMove)
        {
            // Create surogate for file and add it to the folder
            var surrogate     = DataMigrationServices.CreateOwningObjSurElement(fileToMove.Guid);
            var folderElement = XElement.Parse(folder.Xml);
            var filesElement  = folderElement.Element("Files");

            filesElement.Add(surrogate);
            DataMigrationServices.UpdateDTO(repoDto, folder, folderElement.ToString());

            // Change owner of file
            var fileElement = XElement.Parse(fileToMove.Xml);

            fileElement.Attribute("ownerguid").SetValue(folder.Guid);
            DataMigrationServices.UpdateDTO(repoDto, fileToMove, fileElement.ToString());
        }
Exemple #37
0
        // Make a new CmFile element for the specified path, and an objsur child of langCmFolder to own it.
        // In this migration a typical result would be:
        //    <rt guid="c4f4760e-049e-49af-ac57-73c686100700" class="CmFile" ownerguid="3e615e09-3b86-4fae-adfe-5fc2473214b6">
        //    <InternalPath>
        //        <Uni>C:\FwWW\DistFiles\AudioVisual\NotInLinkedFilesPath.WMV</Uni>
        //    </InternalPath>
        //    </rt>
        private void MakeCmFile(IDomainObjectDTORepository domainObjectDtoRepository, string langCmFolderGuid,
                                XElement langCmFolder, string path)
        {
            string cmFileGuid;

            cmFileGuid = Guid.NewGuid().ToString();
            var cmFileXElement = new XElement("rt",
                                              new XAttribute("guid", cmFileGuid),
                                              new XAttribute("class", "CmFile"),
                                              new XAttribute("ownerguid", langCmFolderGuid),
                                              MakeUnicode("InternalPath", path));
            var dtoConfirmed = new DomainObjectDTO(cmFileGuid, "CmFile", cmFileXElement.ToString());

            domainObjectDtoRepository.Add(dtoConfirmed);
            langCmFolder.Element("Files").Add(MakeOwningSurrogate(cmFileGuid));
        }
Exemple #38
0
        private void UpdatePictureReferences(IDomainObjectDTORepository repoDto, DomainObjectDTO file,
                                             string replacementFileGuid,
                                             Dictionary <string, List <DomainObjectDTO> > pictureMap)
        {
            List <DomainObjectDTO> pictures;

            if (pictureMap.TryGetValue(file.Guid, out pictures))
            {
                foreach (var picture in pictures)
                {
                    var pictureElement      = XElement.Parse(picture.Xml);
                    var objSurrogateElement = pictureElement.Element("PictureFile").Element("objsur");
                    objSurrogateElement.Attribute("guid").Value = replacementFileGuid;
                    DataMigrationServices.UpdateDTO(repoDto, picture, pictureElement.ToString());
                }
            }
        }
		private static DomainObjectDTO MakeEvaluation(string ownerGuid, IDomainObjectDTORepository domainObjectDtoRepository, XElement agentElement, string owningAttr)
		{
			var newGuid = Guid.NewGuid().ToString().ToLower();
			var newEvalElt = new XElement("rt",
				new XAttribute("class", "CmAgentEvaluation"),
				new XAttribute("guid", newGuid),
				new XAttribute("ownerguid", ownerGuid),
				new XElement("CmObject"),
				new XElement("CmAgentEvaluation"));
			// Create new dto and add to repos.
			var newEval = new DomainObjectDTO(newGuid, "CmAgentEvaluation", newEvalElt.ToString());
			domainObjectDtoRepository.Add(newEval);
			agentElement.Add(new XElement(owningAttr,
				new XElement("objsur", new XAttribute("t", "o"), new XAttribute("guid", newGuid))));

			return newEval;
		}
Exemple #40
0
        /// <summary>
        /// Change class of object to a new subclass of the original class.
        /// Caller still needs to move it from one collection to another in the repository.
        /// </summary>
        internal static void ChangeToSubClass(DomainObjectDTO target, string oldClass, string newClass)
        {
            ChangeClass(target, oldClass, newClass);
            // Need to fill in the new empty element. It will be right before the closing <\rt>.
            byte[] input = target.XmlBytes;
            int    index = input.Length - ClosingRt.Length;

            for (int i = 0; i < ClosingRt.Length; i++)
            {
                if (input[i + index] != ClosingRt[i])
                {
                    index = input.IndexOfSubArray(ClosingRt);
                }
            }
            byte[] insertBytes = Encoding.UTF8.GetBytes("<" + newClass + "/>");
            target.XmlBytes = input.ReplaceSubArray(index, 0, insertBytes);
        }
		public void DataMigration7000051Test()
		{
			var dtos = new HashSet<DomainObjectDTO>();
			var sb = new StringBuilder();
			// Add Lang Project dto.
			const string sLpGuid = "9719A466-2240-4DEA-9722-9FE0746A30A6";
			const string afxCatGuid = "60ab6c6c-43f3-4a7f-af61-96b4b77648a5";
			sb.AppendFormat("<rt class=\"LangProject\" guid=\"{0}\">", sLpGuid);
			sb.Append("<AffixCategories>");
			sb.AppendFormat("<objsur guid=\"{0}\" t=\"o\" />", afxCatGuid);
			sb.Append("</AffixCategories>");
			sb.Append("</rt>");
			var oldDto = new DomainObjectDTO(sLpGuid, "LangProject", sb.ToString());
			dtos.Add(oldDto);
			sb.Length = 0;

			sb.AppendFormat("<rt class=\"CmPossibilityList\" guid=\"{0}\"  ownerguid=\"{1}\" />", afxCatGuid, sLpGuid);
			var afxCatDto = new DomainObjectDTO(afxCatGuid, "CmPossibilityList", sb.ToString());
			dtos.Add(afxCatDto);

			// Set up mock MDC.
			var mockMDC = new MockMDCForDataMigration();
			mockMDC.AddClass(1, "CmObject", null, new List<string> { "LangProject", "CmPossibilityList" }); // Not true, but no matter.
			mockMDC.AddClass(2, "LangProject", "CmObject", new List<string>());
			mockMDC.AddClass(3, "CmPossibilityList", "CmObject", new List<string>());
			IDomainObjectDTORepository dtoRepos = new DomainObjectDtoRepository(7000050, dtos, mockMDC, null, FwDirectoryFinder.FdoDirectories);

			m_dataMigrationManager.PerformMigration(dtoRepos, 7000051, new DummyProgressDlg());
			Assert.AreEqual(7000051, dtoRepos.CurrentModelVersion, "Wrong updated version.");

			// Check that the old LP is not present.
			DomainObjectDTO gonerDto;
			Assert.IsFalse(dtoRepos.TryGetValue(sLpGuid, out gonerDto));
			Assert.IsTrue(((DomainObjectDtoRepository)dtoRepos).Goners.Contains(oldDto));
			var newDto = dtoRepos.AllInstancesSansSubclasses("LangProject").FirstOrDefault();
			Assert.IsNotNull(newDto);
			Assert.AreNotSame(oldDto, newDto);
			var newDtoGuid = newDto.Guid.ToLowerInvariant();
			Assert.AreNotEqual(sLpGuid.ToLowerInvariant(), newDtoGuid);

			// Check that ownerguid was changed on afxCatDto.
			var afxCatElm = XElement.Parse(afxCatDto.Xml);
			Assert.AreEqual(newDtoGuid, afxCatElm.Attribute("ownerguid").Value.ToLowerInvariant());
		}
		private static void CheckPhPhonData(DomainObjectDTO dtoPhPhonDataTest, IDomainObjectDTORepository dtoRepos)
		{
			var eltWmbPhPhonDataTest = XElement.Parse(dtoPhPhonDataTest.Xml);
			// get phon rule feats
			var eltPhonRuleFeatsTest = eltWmbPhPhonDataTest.Element("PhonRuleFeats");
			Assert.IsNotNull(eltPhonRuleFeatsTest);
			var eltObjsurTest = eltPhonRuleFeatsTest.Element("objsur");
			Assert.IsNotNull(eltObjsurTest);
			// get possibility list itself
			var guidPossibilityListTest = eltObjsurTest.Attribute("guid").Value;
			Assert.IsNotNull(guidPossibilityListTest);
			DomainObjectDTO dtoCmPossiblityTest;
			dtoRepos.TryGetValue(guidPossibilityListTest, out dtoCmPossiblityTest);
			Assert.IsNotNull(dtoCmPossiblityTest);
			var eltWmbCmPossibilityListTest = XElement.Parse(dtoCmPossiblityTest.Xml);
			Assert.IsNotNull(eltWmbCmPossibilityListTest);
			var attrCmPossiblityListClassTest = eltWmbCmPossibilityListTest.Attribute("class").Value;
			Assert.AreEqual("CmPossibilityList", attrCmPossiblityListClassTest);
			var attrCmPossiblityListOwnerGuidTest = eltWmbCmPossibilityListTest.Attribute("ownerguid").Value;
			Assert.AreEqual(dtoPhPhonDataTest.Guid, attrCmPossiblityListOwnerGuidTest);
		}
		static private void AddGlossAppendIfEmpty(IDomainObjectDTORepository dtoRepo, DomainObjectDTO dtoToChange, string glossAppend)
		{
			XElement dtoToChangeElt = XElement.Parse(dtoToChange.Xml);
			XElement glossAppendElt = dtoToChangeElt.XPathSelectElement("GlossAppend");
			if (glossAppendElt == null)
			{
				dtoToChangeElt.Add(XElement.Parse("<GlossAppend/>"));
				glossAppendElt = dtoToChangeElt.XPathSelectElement("GlossAppend");
			}
			XElement aUniElt = glossAppendElt.XPathSelectElement("AUni[@ws='en']");
			if (aUniElt == null)
			{
				glossAppendElt.Add(XElement.Parse("<AUni ws='en'/>"));
				aUniElt = glossAppendElt.XPathSelectElement("AUni[@ws='en']");
			}
			if (aUniElt.Value.Trim().Length == 0)
			{
				aUniElt.Value = glossAppend;
			}

			DataMigrationServices.UpdateDTO(dtoRepo, dtoToChange, dtoToChangeElt.ToString());
		}
		private void FixOrAddMissingTypes(IDomainObjectDTORepository repoDto, IEnumerable<LexTypeInfo> extraTypes)
		{
			foreach (var info in extraTypes)
			{
				var fChanged = false;
				foreach (var xeAUni in info.XmlElement.XPathSelectElements("Name/AUni"))
				{
					var xaWs = xeAUni.Attribute("ws");
					if (xaWs == null || xaWs.Value.ToLowerInvariant() != "en")
						continue;
					var name = xeAUni.Value;
					string guidStd;
					if (!m_mapNameGuid.TryGetValue(name, out guidStd))
						continue;
					// We need to change the guid of this dto from 'guid to 'guidStd
					ChangeInvalidGuid(repoDto, info, name, guidStd);
				}
				var xeProt = info.XmlElement.XPathSelectElement("IsProtected");
				if (xeProt == null)
				{
					info.XmlElement.Add(new XElement("IsProtected", new XAttribute("val", "true")));
					fChanged = true;
				}
				else
				{
					var xaVal = xeProt.Attribute("val");
					if (xaVal == null)
					{
						xeProt.Add(new XAttribute("val", "true"));
						fChanged = true;
					}
					else if (xaVal.Value.ToLowerInvariant() != "true")
					{
						xaVal.SetValue("true");
						fChanged = true;
					}
				}
				if (fChanged)
				{
					info.DTO.Xml = info.XmlElement.ToString();
					repoDto.Update(info.DTO);
				}
			}

			if (m_mapNameGuid.Count > 0)
			{
				BuildNewTypeMaps();
				var newTypes = new HashSet<DomainObjectDTO>();
				foreach (var guid in m_mapGuidName.Keys)
				{
					// We need to create this LexEntryType!
					var rgNewDtos = m_mapGuidNewDtos[guid];
					foreach (var info in rgNewDtos)
					{
						var dto = new DomainObjectDTO(info.Guid, info.ClassName, info.Xml);
						repoDto.Add(dto);
						if (info.ClassName == "LexEntryType")
							newTypes.Add(dto);

					}
				}
				foreach (var dto in newTypes)
				{
					var dtoOwner = repoDto.GetOwningDTO(dto);
					var xeOwner = XElement.Parse(dtoOwner.Xml);
					XElement xePoss = null;
					if (dtoOwner.Classname == "CmPossibilityList")
					{
						xePoss = xeOwner.Element("Possibilities");
						if (xePoss == null)
						{
							xePoss = new XElement("Possibilities");
							xeOwner.Add(xePoss);
						}
					}
					else if (dtoOwner.Classname == "LexEntryType")
					{
						xePoss = xeOwner.Element("SubPossibilities");
						if (xePoss == null)
						{
							xePoss = new XElement("SubPossibilities");
							xeOwner.Add(xePoss);
						}
					}
					if (xePoss != null)
					{
						var fNeeded = true;
						foreach (var objsur in xePoss.Elements("objsur"))
						{
							var xaGuid = objsur.Attribute("guid");
							if (xaGuid == null)
								throw new Exception("missing guid in an objsur element");
							if (xaGuid.Value.Equals(dto.Guid, StringComparison.OrdinalIgnoreCase))
							{
								fNeeded = false;
								break;
							}
						}
						if (fNeeded)
						{
							xePoss.Add(DataMigrationServices.CreateOwningObjSurElement(dto.Guid));
							dtoOwner.Xml = xeOwner.ToString();
							repoDto.Update(dtoOwner);
						}
					}
				}
			}
		}
		public void DataMigration7000001_and_Delint_Tests()
		{
			var dtos = new HashSet<DomainObjectDTO>();
			// 1. Add barebones LP.
			// LP will have one extra property to make sure it isnt; affected.
			// LP will also have a couple 'dangling' references for when 'Delint' is tested.
			// LP will also have an empty Name element that ought to be removed.
			var xml =
				string.Format("<rt class=\"LangProject\" guid=\"9719A466-2240-4DEA-9722-9FE0746A30A6\">{0}" +
					"<CmObject></CmObject>{0}" +
					"<LangProject>{0}" +
						"<Name>{0}" +
						"</Name>{0}" +
						"<FakeBoolProperty val=\"True\" />{0}" +
						"<FakeProperty>bogus content</FakeProperty>{0}" +
						"<EthnologueCode>{0}" +
							"<Uni>ZPI</Uni>{0}" +
						"</EthnologueCode>{0}" +
						"<WordformInventory>{0}" +
							"<objsur guid=\"6C84F84A-5B99-4CF5-A7D5-A308DDC604E0\" t=\"o\"/>{0}" +
						"</WordformInventory>{0}" +
						"<AnalysisStatus>{0}" +
							"<objsur guid=\"44AF225F-964C-4F7B-BE51-1AE05995D38C\" t=\"o\" />{0}" +
						"</AnalysisStatus>{0}" +
						"<CurVernWss>{0}" +
							"<objsur guid=\"D75F7FB5-BABD-4D60-B57F-E188BEF264B7\" t=\"r\"/>{0}" +
						"</CurVernWss>{0}" +
					"</LangProject>{0}" +
				"</rt>", Environment.NewLine);
			var lpDto = new DomainObjectDTO("9719A466-2240-4DEA-9722-9FE0746A30A6",
											"LangProject",
											xml);
			dtos.Add(lpDto);

			xml = string.Format(
				"<rt class=\"WordformInventory\" guid=\"6C84F84A-5B99-4CF5-A7D5-A308DDC604E0\" ownerguid=\"9719A466-2240-4DEA-9722-9FE0746A30A6\" owningflid=\"6001013\" owningord=\"1\">{0}" +
					"<CmObject></CmObject>{0}" +
					"<WordformInventory>{0}" +
						"<Wordforms>{0}" +
							"<objsur guid=\"88304983-CDB2-460B-B3D5-5F95C66F27FF\" t=\"o\" />{0}" +
							"<objsur guid=\"59821DAB-AB03-470E-B430-5696A0503A08\" t=\"o\" />{0}" +
						"</Wordforms>{0}" +
					"</WordformInventory>{0}" +
				"</rt>", Environment.NewLine);
			var wfiDto = new DomainObjectDTO("6C84F84A-5B99-4CF5-A7D5-A308DDC604E0",
											 "WordformInventory",
											 xml);
			dtos.Add(wfiDto);

			// 3. Add two wordforms
			// First wordform.
			xml = string.Format(
				"<rt class=\"WfiWordform\" guid=\"88304983-CDB2-460B-B3D5-5F95C66F27FF\" ownerguid=\"6C84F84A-5B99-4CF5-A7D5-A308DDC604E0\" owningflid=\"5063001\" owningord=\"1\">{0}" +
					"<CmObject></CmObject>{0}" +
					"<WfiWordform>{0}" +
						"<Checksum val=\"1722980789\"/>{0}" +
						"<Form>{0}" +
							"<AUni ws=\"eZPI\">aerekondixyonada</AUni>{0}" +
						"</Form>{0}" +
						"<SpellingStatus val=\"1\"/>{0}" +
					"</WfiWordform>{0}" +
				"</rt>", Environment.NewLine);
			var wf1Dto = new DomainObjectDTO("88304983-CDB2-460B-B3D5-5F95C66F27FF",
											 "WfiWordform",
											 xml);
			dtos.Add(wf1Dto);

			// Second wordform.
			xml = string.Format(
				"<rt class=\"WfiWordform\" guid=\"59821DAB-AB03-470E-B430-5696A0503A08\" ownerguid=\"6C84F84A-5B99-4CF5-A7D5-A308DDC604E0\" owningflid=\"5063001\" owningord=\"2\">{0}" +
					"<CmObject></CmObject>{0}" +
					"<WfiWordform>{0}" +
						"<Checksum val=\"-1933028922\"/>{0}" +
						"<Form>{0}" +
							"<AUni ws=\"eZPI\">aeropwerto</AUni>{0}" +
						"</Form>{0}" +
						"<SpellingStatus val=\"1\"/>{0}" +
					"</WfiWordform>{0}" +
				"</rt>", Environment.NewLine);
			var wf2Dto = new DomainObjectDTO("59821DAB-AB03-470E-B430-5696A0503A08",
											 "WfiWordform",
											 xml);
			dtos.Add(wf2Dto);

			// Add zombie, which is where an object's owner does not exist.
			xml = @"<rt class=""LexSense"" guid=""3462BE3E-4817-4BBE-B2B9-30828B48E2C7"" ownerguid=""0875E978-79C5-4F87-95FE-A4235C0711C1"" owningflid=""5002011"" owningord=""1"" />";
			var zombie = new DomainObjectDTO("3462BE3E-4817-4BBE-B2B9-30828B48E2C7",
											 "LexSense",
											 xml);
			dtos.Add(zombie);
			// Add another zombie,
			// which is where an object's owner *does* exist,
			// but it doesn't know it owns the zombie.
			xml = @"<rt class=""Text"" guid=""c1ecaa72-e382-11de-8a39-0800200c9a66"" ownerguid=""9719A466-2240-4DEA-9722-9FE0746A30A6"" owningflid=""6001006"" owningord=""1"" />";
			var zombie2 = new DomainObjectDTO("c1ecaa72-e382-11de-8a39-0800200c9a66",
											 "Text",
											 xml);
			dtos.Add(zombie2);

			// Set up mock MDC.
			var mockMDC = new MockMDCForDataMigration();
			mockMDC.AddClass(1, "CmObject", null, new List<string> { "LangProject", "Text", "WfiWordform", "LexSense" });
			mockMDC.AddClass(2, "LangProject", "CmObject", new List<string>());
			mockMDC.AddClass(3, "Text", "CmObject", new List<string>());
			mockMDC.AddClass(4, "WfiWordform", "CmObject", new List<string>());
			mockMDC.AddClass(5, "LexSense", "CmObject", new List<string>());
			IDomainObjectDTORepository dtoRepos = new DomainObjectDtoRepository(7000000, dtos, mockMDC, null, FwDirectoryFinder.FdoDirectories);

			m_dataMigrationManager.PerformMigration(dtoRepos, 7000001, new DummyProgressDlg());

			// Make sure version number is correct.
			Assert.AreEqual(7000001, dtoRepos.CurrentModelVersion, "Wrong updated version.");
			// Make sure <rt class=\"LangProject\" ...> has no WFI property.
			var lpElement = XElement.Parse(lpDto.Xml);
			var lpInnerLpElement = lpElement.Element("LangProject");
			Assert.IsNotNull(lpInnerLpElement, "Oops. The 'LangProject' node was also eaten :-(.");

			Assert.IsNull(lpInnerLpElement.Element("WordformInventory"), "Still has WFI in the LangProj element.");

			// Sanity checks.
			Assert.IsNotNull(lpInnerLpElement.Element("EthnologueCode"), "Oops. The 'EthnologueCode' was also eaten :-(.");

			// Make sure there is no WordformInventory <rt> element
			DataMigrationTestServices.CheckDtoRemoved(dtoRepos, wfiDto);

			// Make sure the two wordforms have no owning-related attrs.
			var wfRtElements = new List<XElement> { XElement.Parse(wf1Dto.Xml), XElement.Parse(wf2Dto.Xml) };
			foreach (var wfElement in wfRtElements)
			{
				Assert.IsNull(wfElement.Attribute("ownerguid"), "Still has 'ownerguid'attr.");
				Assert.IsNull(wfElement.Attribute("owningflid"), "Still has 'owningflid'attr.");
				Assert.IsNull(wfElement.Attribute("owningord"), "Still has 'owningord'attr.");
				// Sanity checks.
				Assert.IsNotNull(wfElement.Descendants("WfiWordform").FirstOrDefault(), "Oops. The 'WfiWordform' element was also eaten :-(.");
				Assert.IsNotNull(wfElement.Descendants("Checksum").FirstOrDefault(), "Oops. The 'Checksum' element was also eaten :-(.");
			}

			// [NB: Other unit tests need not check Delint, as once is good enough. :-)]
			// Make sure Delint worked.
			// Make sure dangling owned object was removed.
			var analStatusElement = lpElement.Descendants("AnalysisStatus").FirstOrDefault();
			Assert.IsNull(analStatusElement, "Now empty element was not removed.");
			// Make sure dangling regular reference was removed.
			var curVernWssElement = lpElement.Descendants("CurVernWss").FirstOrDefault();
			Assert.IsNull(curVernWssElement, "Now empty element was not removed.");
			// Make sure zombie was removed.
			DataMigrationTestServices.CheckDtoRemoved(dtoRepos, zombie);
			// Make sure zombie2 was removed.
			DataMigrationTestServices.CheckDtoRemoved(dtoRepos, zombie2);
			// Make sure Delint handled emtpy properties correctly.
			Assert.IsNull(lpInnerLpElement.Element("Name"), "Empty 'Name' property not removed.");
			Assert.IsNotNull(lpInnerLpElement.Element("FakeBoolProperty"), "Oops. 'FakeBoolProperty' removed.");
			Assert.IsNull(lpInnerLpElement.Element("FakeProperty"), "'FakeProperty' survived.");
		}
		/// <summary>
		/// Reset the xml in the DTO and register the DTO as updated with the repository.
		/// Use this overload if the class name is changing.
		/// </summary>
		/// <remarks>
		/// There is no validation of the xml, other than making sure it is not null,
		/// or an emty string.
		/// </remarks>
		internal static void UpdateDTO(IDomainObjectDTORepository dtoRepos,
			DomainObjectDTO dirtball, string newXmlValue, string oldClassName)
		{
			dtoRepos.ChangeClass(dirtball, oldClassName);
			UpdateDTO(dtoRepos, dirtball, newXmlValue);
		}
		private static void UpdateStringsAndProps(IDomainObjectDTORepository domainObjectDtoRepository, DomainObjectDTO dto,
			HashSet<string> referencedWsIds)
		{
			XElement objElem = XElement.Parse(dto.Xml);
			bool modified = false;
			foreach (XElement elem in objElem.Descendants())
			{
				switch (elem.Name.LocalName)
				{
					case "Run":
					case "AStr":
					case "AUni":
						if (UpdateWsAttribute(elem, referencedWsIds))
							modified = true;
						break;

					case "BulNumFontInfo":
					case "Prop":
					case "WsProp":
						if (UpdateWsAttribute(elem, referencedWsIds))
							modified = true;
						if (UpdateFontAttribute(elem))
							modified = true;
						break;
				}
			}
			if (modified)
				DataMigrationServices.UpdateDTO(domainObjectDtoRepository, dto, objElem.ToString());
		}
		private static DomainObjectDTO MakeEvaluation(string ownerGuid, IDomainObjectDTORepository domainObjectDtoRepository, XElement agentElement, string owningAttr)
		{
			var newGuid = Guid.NewGuid().ToString().ToLower();
			var newEvalElt = new XElement("rt",
				new XAttribute("class", "CmAgentEvaluation"),
				new XAttribute("guid", newGuid),
				new XAttribute("ownerguid", ownerGuid),
				new XElement("CmObject"),
				new XElement("CmAgentEvaluation"));
			// Create new dto and add to repos.
			var newEval = new DomainObjectDTO(newGuid, "CmAgentEvaluation", newEvalElt.ToString());
			domainObjectDtoRepository.Add(newEval);
			agentElement.Add(new XElement(owningAttr,
				new XElement("objsur", new XAttribute("t", "o"), new XAttribute("guid", newGuid))));

			return newEval;
		}
			internal LexTypeInfo(DomainObjectDTO dto, XElement xe)
			{
				DTO = dto;
				XmlElement = xe;
			}
		/// <summary>
		/// Changes the GUID of the specified DTO. It updates the owner and all specified referrers to point to the new GUID.
		/// </summary>
		/// <param name="dtoRepos">The dto repos.</param>
		/// <param name="dto">The dto.</param>
		/// <param name="newGuid">The new GUID.</param>
		/// <param name="possibleReferrers">The possible referrers.</param>
		internal static void ChangeGuid(IDomainObjectDTORepository dtoRepos, DomainObjectDTO dto, string newGuid,
			IEnumerable<DomainObjectDTO> possibleReferrers)
		{
			// if the DTO already has the new GUID, don't do anything
			if (dto.Guid.ToLowerInvariant() == newGuid.ToLowerInvariant())
				return;

			XElement rtElem = XElement.Parse(dto.Xml);
			rtElem.Attribute("guid").Value = newGuid;
			dtoRepos.Add(new DomainObjectDTO(newGuid, dto.Classname, rtElem.ToString()));
			foreach (DomainObjectDTO ownedDto in dtoRepos.GetDirectlyOwnedDTOs(dto.Guid))
			{
				XElement ownedElem = XElement.Parse(ownedDto.Xml);
				ownedElem.Attribute("ownerguid").Value = newGuid;
				UpdateDTO(dtoRepos, ownedDto, ownedElem.ToString());
			}

			var ownerDto = dtoRepos.GetOwningDTO(dto);
			if (ownerDto != null)
				UpdateObjSurElement(dtoRepos, ownerDto, dto.Guid, newGuid);

			if (possibleReferrers != null)
			{
				foreach (DomainObjectDTO referrer in possibleReferrers)
					UpdateObjSurElement(dtoRepos, referrer, dto.Guid, newGuid);
			}
			dtoRepos.Remove(dto);
		}
		/// <summary>
		/// Remove <paramref name="goner"/> and everything it owns.
		/// Be sure to include removing goner from its optional owning property.
		/// </summary>
		internal static void RemoveIncludingOwnedObjects(IDomainObjectDTORepository dtoRepos, DomainObjectDTO goner, bool removeFromOwner)
		{
			DomainObjectDTO gonerActual;
			if (!dtoRepos.TryGetValue(goner.Guid, out gonerActual))
				return; // Not in repos.

			if (removeFromOwner)
			{
				var ownerDto = dtoRepos.GetOwningDTO(goner);
				if (ownerDto != null)
				{
					var ownerElement = XElement.Parse(ownerDto.Xml);
					var ownObjSurElement = (from objSurNode in ownerElement.Descendants("objsur")
											where objSurNode.Attribute("t").Value == "o" && objSurNode.Attribute("guid").Value.ToLower() == goner.Guid.ToLower()
											select objSurNode).FirstOrDefault(); // Ought not be null, but play it safe.
					if (ownObjSurElement != null)
						ownObjSurElement.Remove();

					if (!RemoveEmptyPropertyElements(dtoRepos, ownerDto, ownerElement))
					{
						// No empty property elements removed, so we have to do the update.
						UpdateDTO(dtoRepos, ownerDto, ownerElement.ToString());
					}
				}
			}

			foreach (var ownedDto in dtoRepos.GetDirectlyOwnedDTOs(goner.Guid))
				RemoveIncludingOwnedObjects(dtoRepos, ownedDto, false);

			dtoRepos.Remove(goner);
		}
		/// <summary>
		/// Change class of object to a new subclass of the original class.
		/// Caller still needs to move it from one collection to another in the repository.
		/// </summary>
		internal static void ChangeToSubClass(DomainObjectDTO target, string oldClass, string newClass)
		{
			ChangeClass(target, oldClass, newClass);
			// Need to fill in the new empty element. It will be right before the closing <\rt>.
			byte[] input = target.XmlBytes;
			int index = input.Length - ClosingRt.Length;
			for (int i = 0; i < ClosingRt.Length; i++)
				if (input[i + index] != ClosingRt[i])
				{
					index = input.IndexOfSubArray(ClosingRt);
				}
			byte[] insertBytes = Encoding.UTF8.GetBytes("<" + newClass + "/>");
			target.XmlBytes = input.ReplaceSubArray(index, 0, insertBytes);
		}
		private static string[] ExtractReferencedObjects(DomainObjectDTO dto)
		{
			var rootElement = XElement.Parse(dto.Xml);

			return (from objSurElement in rootElement.Descendants("objsur") select objSurElement.Attribute("guid").Value).ToArray();
		}
		/// <summary>
		/// Does two components of changing the class of a DTO representation of the object:
		/// Fixes the class attribute, and fixes the Classname of the DTO.
		/// Caller should arrange to move it from one list to another, and fix the
		/// embedded elements (see e.g. ChangeToSubClass).
		/// </summary>
		/// <param name="target"></param>
		/// <param name="oldClass"></param>
		/// <param name="newClass"></param>
		private static void ChangeClass(DomainObjectDTO target, string oldClass, string newClass)
		{
			// If there's no unexpected white space we can do this efficiently.
			// This depends (like various other code) on NOT having unexpected white space around the '='.
			byte[] classBytes = Encoding.UTF8.GetBytes("class=\"" + oldClass + "\"");
			int index = target.XmlBytes.IndexOfSubArray(classBytes);
			byte[] newClassBytes = Encoding.UTF8.GetBytes("class=\"" + newClass + "\"");
			target.XmlBytes = target.XmlBytes.ReplaceSubArray(index, classBytes.Length, newClassBytes);
			target.Classname = newClass;
		}
		private static bool RemoveEmptyPropertyElements(IDomainObjectDTORepository dtoRepos, DomainObjectDTO currentDto, XContainer rtElement)
		{
			var propertyElements = (rtElement.Element("CmObject") != null)
											? rtElement.Elements().Elements() // Two levels for old stuff before DM15
											: rtElement.Elements();
			// ToArray is required or Remove will end loop early.
			var emptyPropertyElements = (propertyElements.Where(propertyElement => !propertyElement.HasAttributes && !propertyElement.HasElements)).ToArray();
			foreach (var emptyPropertyElement in emptyPropertyElements)
			{
				emptyPropertyElement.Remove();
			}
			// Notify of update, if it changed.
			var results = false;
			if (emptyPropertyElements.Any())
			{
				UpdateDTO(dtoRepos, currentDto, rtElement.ToString());
				results = true;
			}
			return results;
		}
		/// <summary>
		/// Remove a number of objects with a common owner, and everything they own.
		/// </summary>
		internal static void RemoveMultipleIncludingOwnedObjects(IDomainObjectDTORepository dtoRepos,
			List<DomainObjectDTO> goners, DomainObjectDTO ownerDto)
		{
			if (ownerDto != null)
			{
				var ownerElement = XElement.Parse(ownerDto.Xml);
				foreach (var goner in goners)
				{
					var goner1 = goner;
					var ownObjSurElement = (from objSurNode in ownerElement.Descendants("objsur")
											where
												objSurNode.Attribute("t").Value == "o" &&
												objSurNode.Attribute("guid").Value.ToLower() == goner1.Guid.ToLower()
											select objSurNode).FirstOrDefault(); // Ought not be null, but play it safe.
					if (ownObjSurElement != null)
						ownObjSurElement.Remove();
				}
				if (!RemoveEmptyPropertyElements(dtoRepos, ownerDto, ownerElement))
				{
					// No empty property elememtns removed, so we have to do the update.
					UpdateDTO(dtoRepos, ownerDto, ownerElement.ToString());
				}
			}
			foreach (var goner in goners)
			{
				foreach (var ownedDto in dtoRepos.GetDirectlyOwnedDTOs(goner.Guid))
					RemoveIncludingOwnedObjects(dtoRepos, ownedDto, false);
				dtoRepos.Remove(goner);
			}
		}
		/// <summary>
		///
		/// </summary>
		/// <param name="fileDto">This should be a CmFile object.</param>
		/// <returns></returns>
		private string GetCmFilePath(DomainObjectDTO fileDto)
		{
			XElement cmFileXML = XElement.Parse(fileDto.Xml);
			var InternalPath = cmFileXML.XPathSelectElement("InternalPath");
			var filePathFromCmFile = cmFileXML.XPathSelectElement("InternalPath").XPathSelectElement("Uni").Value;
			return filePathFromCmFile;
		}
		private static void UpdateObjSurElement(IDomainObjectDTORepository dtoRepos, DomainObjectDTO dto, string oldGuid, string newGuid)
		{
			var rtElem = XElement.Parse(dto.Xml);
			var ownObjSurGuidAttr = (from objSurNode in rtElem.Descendants("objsur")
									 where objSurNode.Attribute("guid").Value.ToLower() == oldGuid.ToLower()
									 select objSurNode.Attribute("guid")).FirstOrDefault(); // Ought not be null, but play it safe.
			if (ownObjSurGuidAttr != null)
				ownObjSurGuidAttr.Value = newGuid;
			UpdateDTO(dtoRepos, dto, rtElem.ToString());
		}
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Removes the specified field.
		/// </summary>
		/// <param name="dto">The domain transfer object that has a field that may need to be deleted.</param>
		/// <param name="objElement">Name of the object containing fieldToDelete.</param>
		/// <param name="fieldToDelete">The name of the field to delete.</param>
		/// ------------------------------------------------------------------------------------
		private void RemoveField(DomainObjectDTO dto, XElement objElement, string fieldToDelete)
		{
			XElement rmElement = objElement.Element(fieldToDelete);
			if (rmElement != null)
				rmElement.Remove();
		}
		private string GetCmFileGuid(DomainObjectDTO fileDto)
		{
			XElement cmFileXML = XElement.Parse(fileDto.Xml);
			var cmFileGuid = cmFileXML.Attribute("guid").Value;
			return cmFileGuid;
		}