/// ------------------------------------------------------------------------------------ /// <summary> /// Changes all StTxtParas that are owned by Scripture to be ScrTxtParas /// </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 it 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, 7000001); var parasToChangeClasses = new List<DomainObjectDTO>(); foreach (var stTxtPara in domainObjectDtoRepository.AllInstancesSansSubclasses("StTxtPara")) { var paraOwner = domainObjectDtoRepository.GetOwningDTO(stTxtPara); if (paraOwner.Classname != "StText" && paraOwner.Classname != "StFootnote") { continue; // Paragraph is not owned by an StText or StFootnote (shouldn't ever happen) } var textOwner = domainObjectDtoRepository.GetOwningDTO(paraOwner); if (textOwner.Classname != "ScrBook" && textOwner.Classname != "ScrSection") { continue; // StText is not part of Scripture, don't change. } // Its one of the paragraphs that we care about. We just need to change the // class in the xml to be a ScrTxtPara and change the objectsByClass map. DataMigrationServices.ChangeToSubClass(stTxtPara, "StTxtPara", "ScrTxtPara"); parasToChangeClasses.Add(stTxtPara); } // Udate the repository var startingStructure = new ClassStructureInfo("StPara", "StTxtPara"); var endingStructure = new ClassStructureInfo("StTxtPara", "ScrTxtPara"); foreach (var changedPara in parasToChangeClasses) domainObjectDtoRepository.Update(changedPara, startingStructure, endingStructure); DataMigrationServices.IncrementVersionNumber(domainObjectDtoRepository); }
private Dictionary <string, List <DomainObjectDTO> > CreateFileGuidToPictureMap(IDomainObjectDTORepository repoDto) { var map = new Dictionary <string, List <DomainObjectDTO> >(); foreach (var picture in repoDto.AllInstancesSansSubclasses("CmPicture")) { // all TE pictures are unowned, so no need to look at those with owners if (repoDto.GetOwningDTO(picture) == null) { var pictureElement = XElement.Parse(picture.Xml); var pictureFileElement = pictureElement.Element("PictureFile"); // FWR-3385: not sure how this could happen, but it has occurred in // real data if (pictureFileElement == null) { continue; } var objSurrogateElement = pictureFileElement.Element("objsur"); var fileGuid = objSurrogateElement.Attribute("guid").Value; List <DomainObjectDTO> list; if (!map.TryGetValue(fileGuid, out list)) { list = new List <DomainObjectDTO>(); map[fileGuid] = list; } list.Add(picture); } } return(map); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Changes all StTxtParas that are owned by Scripture to be ScrTxtParas /// </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 it 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, 7000001); var parasToChangeClasses = new List <DomainObjectDTO>(); foreach (var stTxtPara in domainObjectDtoRepository.AllInstancesSansSubclasses("StTxtPara")) { var paraOwner = domainObjectDtoRepository.GetOwningDTO(stTxtPara); if (paraOwner.Classname != "StText" && paraOwner.Classname != "StFootnote") { continue; // Paragraph is not owned by an StText or StFootnote (shouldn't ever happen) } var textOwner = domainObjectDtoRepository.GetOwningDTO(paraOwner); if (textOwner.Classname != "ScrBook" && textOwner.Classname != "ScrSection") { continue; // StText is not part of Scripture, don't change. } // Its one of the paragraphs that we care about. We just need to change the // class in the xml to be a ScrTxtPara and change the objectsByClass map. DataMigrationServices.ChangeToSubClass(stTxtPara, "StTxtPara", "ScrTxtPara"); parasToChangeClasses.Add(stTxtPara); } // Udate the repository var startingStructure = new ClassStructureInfo("StPara", "StTxtPara"); var endingStructure = new ClassStructureInfo("StTxtPara", "ScrTxtPara"); foreach (var changedPara in parasToChangeClasses) { domainObjectDtoRepository.Update(changedPara, startingStructure, endingStructure); } DataMigrationServices.IncrementVersionNumber(domainObjectDtoRepository); }
/// <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> /// 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); }
private void VerifyStylesRenamedOrDeleted(IDomainObjectDTORepository repoDTO) { int cHyperlink = 0; int cWrtSysAbbr = 0; int cExternalLink = 0; int cInternalLink = 0; int cLanguageCode = 0; int cStrong = 0; int cBuiltIn = 0; int cCustom = 0; bool gotHeading3 = false; bool gotHeading5 = false; foreach (DomainObjectDTO dto in repoDTO.AllInstancesSansSubclasses("StStyle")) { Assert.That(dto.Guid.ToUpper(), Is.Not.EqualTo("71B2233D-8B14-42D5-A625-AAC8EDE7503B"), "Heading 3 in LexDb duplicates one in LangProj and should have been deleted"); if (dto.Guid.ToUpper() == "B82D12DE-EA5E-11DE-88CD-0013722F8DEC") // Keeper Heading 3 { gotHeading3 = true; var h3Elt = XElement.Parse(dto.Xml); Assert.That(h3Elt.Element("Rules").Element("Prop").Attribute("fontFamily").Value, Is.EqualTo("Times New Roman"), "should transfer font family setting from lexDB version of heading 3 to lang proj"); Assert.That(h3Elt.Element("Rules").Element("Prop").Attribute("fontsize").Value, Is.EqualTo("11000"), "should transfer font size setting from lexDB version of heading 3 to lang proj"); Assert.That(h3Elt.Element("BasedOn").Element("objsur").Attribute("guid").Value.ToUpperInvariant, Is.EqualTo("B8238980-EA5E-11DE-86E1-0013722F8DEC"), "should transfer based-on information to corresponding style in langproj"); Assert.That(h3Elt.Element("Next").Element("objsur").Attribute("guid").Value.ToUpperInvariant, Is.EqualTo("B8179DD2-EA5E-11DE-8537-0013722F8DEC"), "should transfer next information to corresponding style in langproj"); } if (dto.Guid.ToUpper() == "44944544-DF17-4553-94B8-A5E13C3392C5") // keeper Heading 5 { gotHeading5 = true; var h5Elt = XElement.Parse(dto.Xml); Assert.That(h5Elt.Element("BasedOn").Element("objsur").Attribute("guid").Value.ToUpperInvariant, Is.EqualTo("B8238980-EA5E-11DE-86E1-0013722F8DEC"), "should transfer based-on information to corresponding style in langproj"); Assert.That(h5Elt.Element("Next").Element("objsur").Attribute("guid").Value.ToUpperInvariant, Is.EqualTo("B8179DD2-EA5E-11DE-8537-0013722F8DEC"), "should transfer next information to corresponding style in langproj"); } string sXml = dto.Xml; string sName = GetStyleName(sXml); DomainObjectDTO dtoOwner = repoDTO.GetOwningDTO(dto); if (dtoOwner.Classname != "LangProject") { Assert.AreEqual(dtoOwner.Classname, "Scripture", "Either LangProject or Scripture owns the style"); if (sName == "External Link") { ++cExternalLink; } else if (sName == "Internal Link") { ++cInternalLink; } else if (sName == "Language Code") { ++cLanguageCode; } } else { Assert.AreNotEqual(sName, "External Link", "The External Link style should no longer exist"); Assert.AreNotEqual(sName, "Internal Link", "The Internal Link style should no longer exist"); Assert.AreNotEqual(sName, "Language Code", "The Language Code style should no longer exist"); if (sName == "Hyperlink") { ++cHyperlink; } else if (sName == "Writing System Abbreviation") { ++cWrtSysAbbr; } else if (sName == "Strong") { ++cStrong; } if (sXml.Contains("<BasedOn>") || sXml.Contains("<Next>")) { XElement xeStyle = XElement.Parse(sXml); ValidateStyleReference(repoDTO, xeStyle, "BasedOn"); ValidateStyleReference(repoDTO, xeStyle, "Next"); } switch (sName) { case "Normal": case "Numbered List": case "Bulleted List": case "Heading 1": case "Heading 2": case "Heading 3": case "Block Quote": case "Title Text": case "Emphasized Text": case "Writing System Abbreviation": case "Added Text": case "Deleted Text": case "Hyperlink": case "Strong": case "Dictionary-Normal": case "Classified-MainEntry": case "Classified-Item": Assert.IsTrue(IsBuiltInStyle(sXml), sName + " should be marked as built-in"); ++cBuiltIn; break; default: // "Heading 4" and "Dictionary-Custom" should pass through here, plus 7 more // created from direct formatting. Assert.IsFalse(IsBuiltInStyle(sXml), sName + " should not be marked as built-in"); ++cCustom; break; } } } Assert.That(gotHeading3, "should have kept the LangProj Heading3"); Assert.That(gotHeading5, "should have kept the LangProj Heading4"); Assert.AreEqual(1, cHyperlink, "The Hyperlink style should exist (once)"); Assert.AreEqual(1, cWrtSysAbbr, "The Writing System Abbreviation style should exist (once)"); Assert.AreEqual(1, cStrong, "The Strong style should exist (once)"); Assert.AreEqual(1, cExternalLink, "The External Link style should exist (once) in the Scripture stylesheet"); Assert.AreEqual(1, cInternalLink, "The Internal Link style should exist (once) in the Scripture stylesheet"); Assert.AreEqual(1, cLanguageCode, "The Language Code style should exist (once) in the Scripture stylesheet"); Assert.AreEqual(17, cBuiltIn, "There should be 17 built-in LangProject styles."); Assert.AreEqual(9, cCustom, "There should be 9 custom LangProject styles."); }
/// <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); }
private void VerifyStylesRenamedOrDeleted(IDomainObjectDTORepository repoDTO) { int cHyperlink = 0; int cWrtSysAbbr = 0; int cExternalLink = 0; int cInternalLink = 0; int cLanguageCode = 0; int cStrong = 0; int cBuiltIn = 0; int cCustom = 0; bool gotHeading3 = false; bool gotHeading5 = false; foreach (DomainObjectDTO dto in repoDTO.AllInstancesSansSubclasses("StStyle")) { Assert.That(dto.Guid.ToUpper(), Is.Not.EqualTo("71B2233D-8B14-42D5-A625-AAC8EDE7503B"), "Heading 3 in LexDb duplicates one in LangProj and should have been deleted"); if (dto.Guid.ToUpper() == "B82D12DE-EA5E-11DE-88CD-0013722F8DEC") // Keeper Heading 3 { gotHeading3 = true; var h3Elt = XElement.Parse(dto.Xml); Assert.That(h3Elt.Element("Rules").Element("Prop").Attribute("fontFamily").Value, Is.EqualTo("Times New Roman"), "should transfer font family setting from lexDB version of heading 3 to lang proj"); Assert.That(h3Elt.Element("Rules").Element("Prop").Attribute("fontsize").Value, Is.EqualTo("11000"), "should transfer font size setting from lexDB version of heading 3 to lang proj"); Assert.That(h3Elt.Element("BasedOn").Element("objsur").Attribute("guid").Value.ToUpperInvariant, Is.EqualTo("B8238980-EA5E-11DE-86E1-0013722F8DEC"), "should transfer based-on information to corresponding style in langproj"); Assert.That(h3Elt.Element("Next").Element("objsur").Attribute("guid").Value.ToUpperInvariant, Is.EqualTo("B8179DD2-EA5E-11DE-8537-0013722F8DEC"), "should transfer next information to corresponding style in langproj"); } if (dto.Guid.ToUpper() == "44944544-DF17-4553-94B8-A5E13C3392C5") // keeper Heading 5 { gotHeading5 = true; var h5Elt = XElement.Parse(dto.Xml); Assert.That(h5Elt.Element("BasedOn").Element("objsur").Attribute("guid").Value.ToUpperInvariant, Is.EqualTo("B8238980-EA5E-11DE-86E1-0013722F8DEC"), "should transfer based-on information to corresponding style in langproj"); Assert.That(h5Elt.Element("Next").Element("objsur").Attribute("guid").Value.ToUpperInvariant, Is.EqualTo("B8179DD2-EA5E-11DE-8537-0013722F8DEC"), "should transfer next information to corresponding style in langproj"); } string sXml = dto.Xml; string sName = GetStyleName(sXml); DomainObjectDTO dtoOwner = repoDTO.GetOwningDTO(dto); if (dtoOwner.Classname != "LangProject") { Assert.AreEqual(dtoOwner.Classname, "Scripture", "Either LangProject or Scripture owns the style"); if (sName == "External Link") ++cExternalLink; else if (sName == "Internal Link") ++cInternalLink; else if (sName == "Language Code") ++cLanguageCode; } else { Assert.AreNotEqual(sName, "External Link", "The External Link style should no longer exist"); Assert.AreNotEqual(sName, "Internal Link", "The Internal Link style should no longer exist"); Assert.AreNotEqual(sName, "Language Code", "The Language Code style should no longer exist"); if (sName == "Hyperlink") ++cHyperlink; else if (sName == "Writing System Abbreviation") ++cWrtSysAbbr; else if (sName == "Strong") ++cStrong; if (sXml.Contains("<BasedOn>") || sXml.Contains("<Next>")) { XElement xeStyle = XElement.Parse(sXml); ValidateStyleReference(repoDTO, xeStyle, "BasedOn"); ValidateStyleReference(repoDTO, xeStyle, "Next"); } switch (sName) { case "Normal": case "Numbered List": case "Bulleted List": case "Heading 1": case "Heading 2": case "Heading 3": case "Block Quote": case "Title Text": case "Emphasized Text": case "Writing System Abbreviation": case "Added Text": case "Deleted Text": case "Hyperlink": case "Strong": case "Dictionary-Normal": case "Classified-MainEntry": case "Classified-Item": Assert.IsTrue(IsBuiltInStyle(sXml), sName + " should be marked as built-in"); ++cBuiltIn; break; default: // "Heading 4" and "Dictionary-Custom" should pass through here, plus 7 more // created from direct formatting. Assert.IsFalse(IsBuiltInStyle(sXml), sName + " should not be marked as built-in"); ++cCustom; break; } } } Assert.That(gotHeading3, "should have kept the LangProj Heading3"); Assert.That(gotHeading5, "should have kept the LangProj Heading4"); Assert.AreEqual(1, cHyperlink, "The Hyperlink style should exist (once)"); Assert.AreEqual(1, cWrtSysAbbr, "The Writing System Abbreviation style should exist (once)"); Assert.AreEqual(1, cStrong, "The Strong style should exist (once)"); Assert.AreEqual(1, cExternalLink, "The External Link style should exist (once) in the Scripture stylesheet"); Assert.AreEqual(1, cInternalLink, "The Internal Link style should exist (once) in the Scripture stylesheet"); Assert.AreEqual(1, cLanguageCode, "The Language Code style should exist (once) in the Scripture stylesheet"); Assert.AreEqual(17, cBuiltIn, "There should be 17 built-in LangProject styles."); Assert.AreEqual(9, cCustom, "There should be 9 custom LangProject styles."); }
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); } } } } }
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; }
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 Dictionary<string, List<DomainObjectDTO>> CreateFileGuidToPictureMap(IDomainObjectDTORepository repoDto) { var map = new Dictionary<string, List<DomainObjectDTO>>(); foreach (var picture in repoDto.AllInstancesSansSubclasses("CmPicture")) { // all TE pictures are unowned, so no need to look at those with owners if (repoDto.GetOwningDTO(picture) == null) { var pictureElement = XElement.Parse(picture.Xml); var pictureFileElement = pictureElement.Element("PictureFile"); // FWR-3385: not sure how this could happen, but it has occurred in // real data if (pictureFileElement == null) continue; var objSurrogateElement = pictureFileElement.Element("objsur"); var fileGuid = objSurrogateElement.Attribute("guid").Value; List<DomainObjectDTO> list; if (!map.TryGetValue(fileGuid, out list)) { list = new List<DomainObjectDTO>(); map[fileGuid] = list; } list.Add(picture); } } return map; }
private static string GetStTextGuidFromXfic(IDomainObjectDTORepository dtoRepos, string xficGuid) { var dtoXfic = dtoRepos.GetDTO(xficGuid.ToLowerInvariant()); var paraGuid = GetBeginObjectGuid(dtoXfic.XmlBytes); return dtoRepos.GetOwningDTO(dtoRepos.GetDTO(paraGuid.ToLowerInvariant())).Guid; }
private static void DeleteUnneededGoners(IDomainObjectDTORepository dtoRepos, IEnumerable<DomainObjectDTO> goners, ICollection<string> neededGoners) { // We have run out of memory during this data migration on large projects. (See // FWR-3849.) One possible reason is that we can make 15000+ copies of LangProject // as we slowly squeeze out the owning links to Annotations. So let's collect them // all up at once, and remove them with a single change to the LangProject dto. var dtoLangProject = dtoRepos.AllInstancesSansSubclasses("LangProject").FirstOrDefault(); if (dtoLangProject != null) { var xeLangProject = XElement.Parse(dtoLangProject.Xml); var cAnn = xeLangProject.Descendants("objsur"). Where(t => (t.Attribute("t") != null && t.Attribute("t").Value == "o")).Count(); if (cAnn > 0) { var gonersInLangProject = new List<DomainObjectDTO>(cAnn); foreach (var goner in goners) { DomainObjectDTO gonerActual; if (!dtoRepos.TryGetValue(goner.Guid, out gonerActual)) continue; // Not in repos. if (neededGoners.Contains(goner.Guid)) continue; // still need this in the repository. var ownerDto = dtoRepos.GetOwningDTO(goner); if (ownerDto != null && ownerDto.Guid == dtoLangProject.Guid) gonersInLangProject.Add(gonerActual); } if (gonersInLangProject.Count > 0) { DataMigrationServices.RemoveMultipleIncludingOwnedObjects(dtoRepos, gonersInLangProject, dtoLangProject); gonersInLangProject.Clear(); // We don't try removing those from goners because that operation may // involve a linear lookup in the list to find the object to remove. // And RemoveIncludingOwnedObjects() checks whether the goner still // exists before doing anything else. } } } // Remove old stuff. foreach (var goner in goners) { if (neededGoners.Contains(goner.Guid)) continue; DataMigrationServices.RemoveIncludingOwnedObjects(dtoRepos, goner, true); } }
private static XElement AddSegmentAnalyses( IDomainObjectDTORepository dtoRepos, IEnumerable<KeyValuePair<byte[], XElement>> halfBakedCcwgItemsForCurrentPara, byte[] oldSegElement, IDictionary<int, byte[]> xficsForCurrentPara, ICollection<byte[]> oldTextTags, string newSegmentGuid, bool isLastOldSegment, DomainObjectDTO paraDto) { XElement retval = null; var oldSegBeginOffset = GetBeginOffset(oldSegElement); var oldSegEndOffset = GetEndOffset(oldSegElement); var xficsForCurrentOldSegment = new SortedList<int, byte[]>(); var halfBakedCcwgsForCurrentOldSegment = new List<XElement>(); if (xficsForCurrentPara != null) { foreach (var kvp in xficsForCurrentPara) { var xficGuid = GetGuid(kvp.Value); var beginOffset = kvp.Key; // Try to find a CCWG that has a matching instanceOfGuid. XElement halfBakedCcwg = null; foreach (var halfBakedKvp in halfBakedCcwgItemsForCurrentPara) { // NB: halfBakedKvp.Value.Element("ConstChartWordGroup").Element("BeginAnalysisIndex").Attribute("val").Value.ToLower() // This is the 'InstanceOf' guid of the xfic, not the xfic's guid. if ( halfBakedKvp.Value.Element("ConstChartWordGroup").Element("BeginAnalysisIndex").Attribute( "val").Value.ToLower() != xficGuid) continue; // If there happen to be more than one CCWG pointing to the same xfic, only one gets 'finished'! halfBakedCcwg = halfBakedKvp.Value; break; } if (beginOffset >= oldSegBeginOffset && beginOffset < oldSegEndOffset) { xficsForCurrentOldSegment.Add(beginOffset, kvp.Value); if (halfBakedCcwg != null) halfBakedCcwgsForCurrentOldSegment.Add(halfBakedCcwg); } else if (isLastOldSegment) { if (halfBakedCcwg != null) halfBakedCcwgsForCurrentOldSegment.Add(halfBakedCcwg); xficsForCurrentOldSegment.Add(beginOffset, kvp.Value); } } } if (xficsForCurrentOldSegment.Count > 0) { foreach (var key in xficsForCurrentOldSegment.Keys) xficsForCurrentPara.Remove(key); // The one returned element is "Analyses" (or null, if no twfics/pfics). // It will have one, or more, 'objsur' type 'r' elements in it. // The 'Analyses' property is a seq, // which is why is xficsForCurrentOldSegment is sorted the BeginOffset of the contained twfics/pfics. // All xfics will have an 'InstanceOf' by now, even pfics. // The pfics had a new InstanceOf prop set earlier // (or were removed, if InstanceOf could not be set), // and twfics with no InstanceOf prop were filtered out earlier. retval = new XElement("Analyses", from xfix in xficsForCurrentOldSegment.Values select DataMigrationServices.CreateReferenceObjSurElement(GetInstanceOfGuid(xfix))); // Finish converting half-baked CCWG stuff. if (halfBakedCcwgsForCurrentOldSegment.Count > 0) { var allOldXficGuids = (from xfix in xficsForCurrentOldSegment.Values select GetGuid(xfix).ToLower()).ToList(); foreach (var halfBakedCcwg in halfBakedCcwgsForCurrentOldSegment) { // Fix up halfbaked CCWG items here. var innerElement = halfBakedCcwg.Element("ConstChartWordGroup"); // NB: The guids temporarily stored in the begin/end index props are for // the xfic guid, but we want to look up the index of its InstanceOf property, // which will be what is actually in the new "Analyses" prop of the new Segment. var guidAttr = innerElement.Element("BeginAnalysisIndex").Attribute("val"); guidAttr.Value = allOldXficGuids.IndexOf(guidAttr.Value.ToLower()).ToString(); guidAttr = innerElement.Element("EndAnalysisIndex").Attribute("val"); guidAttr.Value = allOldXficGuids.IndexOf(guidAttr.Value.ToLower()).ToString(); // NB: The recently created CCWG has already been added to dto repos, // so the only remaining task is to update the xml on the CCWG dto. var dto = dtoRepos.GetDTO(GetGuid(halfBakedCcwg)); dto.Xml = halfBakedCcwg.ToString(); } } // Find and convert any any old Text Tag indirect annotations for this segment. // NB: xficsForCurrentOldSegment.Values may have pfics, // and we don't want those here. // oldTextTags is all old TextTag annotations for everything. // This variable holds the twfics (in BeginOffset order), // where pfics are removed from xficsForCurrentOldSegment. var twficBeginOffsetListForCurrentSegment = new List<int>(); var twficGuidListForCurrentSegment = new List<string>(); var twficElementListForCurrentSegment = new List<byte[]>(); var twficMap = new Dictionary<string, byte[]>(); foreach (var twficKvp in from xficKvp in xficsForCurrentOldSegment where GetAnnotationTypeGuid(xficKvp.Value) == DataMigrationServices.kTwficAnnDefnGuid select xficKvp) { twficBeginOffsetListForCurrentSegment.Add(twficKvp.Key); var twficGuid = GetGuid(twficKvp.Value); twficGuidListForCurrentSegment.Add(twficGuid); twficElementListForCurrentSegment.Add(twficKvp.Value); twficMap.Add(twficGuid, twficKvp.Value); } var textTagElementsForCurrentSegment = new List<byte[]>(); foreach (var oldTextTagAnnElement in oldTextTags) { // Find the ones that are used in the current segment, // and add them to textTagElementsForCurrentSegment. var appliesToGuids = new List<string>(); foreach (var guid in GetAppliesToObjsurGuids(oldTextTagAnnElement)) { if (twficGuidListForCurrentSegment.Contains(guid)) appliesToGuids.Add(guid); } if (appliesToGuids.Count() <= 0) continue; // Store them for a while. textTagElementsForCurrentSegment.Add(oldTextTagAnnElement); // Get the index of the First twfic in appliesToGuids collection (which may hold pfics) // and the index of the Last twfic in appliesToGuids collection (which may hold pfics). var beginIdx = 0; for (var i = 0; i < appliesToGuids.Count(); ++i) { var currentXfixGuid = appliesToGuids[i].ToLower(); byte[] currentTwficElement; if (!twficMap.TryGetValue(currentXfixGuid, out currentTwficElement)) continue; beginIdx = xficsForCurrentOldSegment.IndexOfValue(currentTwficElement); break; } var endIdx = 0; for (var i = appliesToGuids.Count() - 1; i > -1; --i) { var currentXfixGuid = appliesToGuids[i].ToLower(); byte[] currentTwficElement; if (!twficMap.TryGetValue(currentXfixGuid, out currentTwficElement)) continue; endIdx = xficsForCurrentOldSegment.IndexOfValue(currentTwficElement); break; } var owningStText = dtoRepos.GetOwningDTO(paraDto); var newTextTagGuid = Guid.NewGuid().ToString().ToLower(); var newTextTagElement = new XElement("rt", new XAttribute("class", "TextTag"), new XAttribute("guid", newTextTagGuid), new XAttribute("ownerguid", owningStText.Guid.ToLower()), new XElement("CmObject"), new XElement("TextTag", new XElement("BeginSegment", DataMigrationServices.CreateReferenceObjSurElement(newSegmentGuid)), new XElement("EndSegment", DataMigrationServices.CreateReferenceObjSurElement(newSegmentGuid)), new XElement("BeginAnalysisIndex", new XAttribute("val", beginIdx)), new XElement("EndAnalysisIndex", new XAttribute("val", endIdx)), new XElement("Tag", DataMigrationServices.CreateReferenceObjSurElement(GetInstanceOfGuid(oldTextTagAnnElement))))); // Add new DTO to repos. var newTextTagDto = new DomainObjectDTO(newTextTagGuid, "TextTag", newTextTagElement.ToString()); dtoRepos.Add(newTextTagDto); // Add new TextTag to owning prop on owner as objsur element. var owningStTextElement = XElement.Parse(owningStText.Xml); var innerStTextElement = owningStTextElement.Element("StText"); var tagsPropElement = innerStTextElement.Element("Tags"); if (tagsPropElement == null) { tagsPropElement = new XElement("Tags"); innerStTextElement.Add(tagsPropElement); } tagsPropElement.Add(DataMigrationServices.CreateOwningObjSurElement(newTextTagGuid)); // Tell repos of the modification. owningStText.Xml = owningStTextElement.ToString(); dtoRepos.Update(owningStText); } // Remove current text tags from input list foreach (var currentTextTagElement in textTagElementsForCurrentSegment) oldTextTags.Remove(currentTextTagElement); } //else //{ // // No xfics at all, so make sure para is set to be tokenized again. // // Done globally for each Para in ProcessParagraphs // //MarkParaAsNeedingTokenization(dtoRepos, paraDto, paraElement); //} return retval; }