private static void CheckNewPropertyAfterUpgrade(FdoClassInfo classInfo, string newPropName, DataType dataType) { var newProperty = GetProperty(classInfo, newPropName); Assert.IsNotNull(newProperty, string.Format("{0} {1} should exist now.", classInfo.ClassName, newPropName)); Assert.AreEqual(dataType, newProperty.DataType, string.Format("{0} {1} data type should be {2}.", classInfo.ClassName, newPropName, dataType)); }
private static string ChangeGuids(MetadataCache mdc, FdoClassInfo classInfo, XElement element) { var newGuid = Guid.NewGuid().ToString().ToLowerInvariant(); element.Attribute(SharedConstants.GuidStr).Value = newGuid; // Recurse down through everything that is owned and change those guids. foreach (var owningPropInfo in classInfo.AllOwningProperties) { var isCustomProp = owningPropInfo.IsCustomProperty; var owningPropElement = isCustomProp ? (element.Elements(SharedConstants.Custom).Where(customProp => customProp.Attribute(SharedConstants.Name).Value == owningPropInfo.PropertyName)).FirstOrDefault() : element.Element(owningPropInfo.PropertyName); if (owningPropElement == null || !owningPropElement.HasElements) { continue; } foreach (var ownedElement in owningPropElement.Elements()) { FdoClassInfo ownedClassInfo; string className; GetClassInfoFromElement(mdc, element, out ownedClassInfo, out className); ChangeGuids(mdc, ownedClassInfo, ownedElement); } } return(newGuid); }
private static void CheckNewPropertyAfterUpgrade(FdoClassInfo classInfo, string newPropName, DataType dataType) { var newProperty = (from propInfo in classInfo.AllProperties where propInfo.PropertyName == newPropName select propInfo).FirstOrDefault(); Assert.IsNotNull(newProperty, string.Format("{0} {1} should exist now.", classInfo.ClassName, newPropName)); Assert.AreEqual(dataType, newProperty.DataType, string.Format("{0} {1} data type should be {2}.", classInfo.ClassName, newPropName, dataType)); }
/// <summary> /// Gets the 'label' attribute of the custom property, if present, or its 'name', if not present. /// </summary> /// <param name="classname">Class name that is supposed to contain the given custom property.</param> /// <param name="customPropertyName">Name from Custom element which is an ancestor of styleRules (for a custom field)</param> /// <returns>The label of the custom field if it has one. Otherwise, the custom property name.</returns> public string GetDisplayName(string classname, string customPropertyName) { var mdc = MetadataCache.MdCache; FdoClassInfo classInfo = null; if (string.IsNullOrEmpty(classname)) { // Find it the hard way. foreach (var fdoClassInfo in mdc.AllClasses .Where(fdoClassInfo => fdoClassInfo.AllProperties.Any(propInf => propInf.DataType == DataType.TextPropBinary && propInf.PropertyName == customPropertyName))) { classInfo = fdoClassInfo; break; } } else { classInfo = mdc.GetClassInfo(classname); } if (classInfo == null) { return(customPropertyName); } var propInfo = classInfo.GetProperty(customPropertyName); if (propInfo == null || !propInfo.IsCustomProperty) { return(customPropertyName); } var allPropInfo = propInfo.AllPropertyValues; return(allPropInfo.ContainsKey(SharedConstants.Label) ? allPropInfo[SharedConstants.Label] : customPropertyName); }
private static FdoClassInfo CheckClassDoesExistAfterUpGrade(MetadataCache mdc, FdoClassInfo superclass, string newClassname) { var result = mdc.GetClassInfo(newClassname); Assert.IsNotNull(result); Assert.AreSame(superclass, result.Superclass); return(result); }
private static void MakeClassStrategy(MergeStrategies strategiesForMerger, FdoClassInfo classInfo, FieldWorkObjectContextGenerator defaultDescriptor) { Guard.AgainstNull(defaultDescriptor, "defaultDescriptor"); // These values can be overridden or added to in the big switch, below. var classStrat = new ElementStrategy(false) { ContextDescriptorGenerator = defaultDescriptor, MergePartnerFinder = GuidKeyFinder, IsAtomic = false }; strategiesForMerger.SetStrategy(classInfo.ClassName, classStrat); // Try to keep these in alphbetical order, and where there are 'blocks', then try to keep the blocks in order. // That will make them easier to find. switch (classInfo.ClassName) { case "CmPossibilityList": classStrat.ContextDescriptorGenerator = new PossibilityListContextGenerator(); break; case "FsClosedFeature": classStrat.ContextDescriptorGenerator = new MultiLingualStringsContextGenerator("Phonological Features", "Name", "Abbreviation"); break; case "FsFeatStruc": classStrat.IsAtomic = true; break; case "LangProject": classStrat.ContextDescriptorGenerator = new LanguageProjectContextGenerator(); break; case "LexEntry": classStrat.ContextDescriptorGenerator = new LexEntryContextGenerator(); break; case "PhEnvironment": classStrat.ContextDescriptorGenerator = new EnvironmentContextGenerator(); break; case "PhNCSegments": classStrat.ContextDescriptorGenerator = new MultiLingualStringsContextGenerator("Natural Class", "Name", "Abbreviation"); break; case "ReversalIndexEntry": classStrat.ContextDescriptorGenerator = new ReversalEntryContextGenerator(); break; case "RnGenericRec": classStrat.ContextDescriptorGenerator = new RnGenericRecContextGenerator(); break; case "ScrBook": classStrat.ContextDescriptorGenerator = new ScrBookContextGenerator(); break; case "ScrDraft": // ScrDraft instances can only be added or removed, but not changed, according to John Wickberg (18 Jan 2012). classStrat.IsImmutable = true; break; case "ScrSection": classStrat.ContextDescriptorGenerator = new ScrSectionContextGenerator(); break; case "ScrTxtPara": // Fall through. case "StTxtPara": // This will never be used, since StTxtParas & ScrTxtParas are actually in an 'ownseq' element. classStrat.Premerger = new StTxtParaPremerger(); // Didn't work, since StTxtParas & ScrTxtParas are actually in an 'ownseq' element. // classStrat.IsAtomic = true; break; case "Text": classStrat.ContextDescriptorGenerator = new TextContextGenerator(); break; case "WfiWordform": classStrat.ContextDescriptorGenerator = new WfiWordformContextGenerator(); break; // These should be all the subclasses of CmPossiblity. It's unfortuate to have to list them here; // OTOH, if we ever want special handling for any of them, we can easily add a special generator. // Note that these will not usually be found as strategies, since they are owned in owning sequences // and ownseq has its own item. However, they can be found by the default object context generator code, // which has a special case for ownseq. case "ChkTerm": case "CmAnthroItem": case "CmAnnotationDefn": case "CmCustomItem": case "CmLocation": case "CmPerson": case "CmPossibility": case "CmSemanticDomain": case "LexEntryType": case "LexRefType": case "MoMorphType": case "PartOfSpeech": case "PhPhonRuleFeat": classStrat.ContextDescriptorGenerator = new PossibilityContextGenerator(); break; case "ConstChartRow": case "ConstChartWordGroup": case "DsConstChart": classStrat.ContextDescriptorGenerator = new DiscourseChartContextGenerator(); break; } ((FieldWorkObjectContextGenerator)classStrat.ContextDescriptorGenerator).MergeStrategies = strategiesForMerger; }
private static void AddPropertyStrategiesForClass(MergeStrategies strategiesForMerger, FdoClassInfo classInfo) { foreach (var propertyInfo in classInfo.AllProperties) { var isCustom = propertyInfo.IsCustomProperty; var propStrategy = isCustom ? CreateStrategyForKeyedElement(SharedConstants.Name, false) : CreateSingletonElementStrategy(); switch (propertyInfo.DataType) { // Block of object properties case DataType.OwningAtomic: propStrategy.NumberOfChildren = NumberOfChildrenAllowed.ZeroOrOne; break; //case DataType.OwningCollection: // Nothing special done // break; case DataType.OwningSequence: if ((classInfo.ClassName == "CmPossibilityList" && propertyInfo.PropertyName == "Possibilities") || (propertyInfo.PropertyName == "SubPossibilities" && classInfo.IsOrInheritsFrom("CmPossibility"))) { // Order may or may not be significant in possibility lists and sublists, depending on whether the list is sorted. propStrategy.ChildOrderPolicy = new PossibilityListOrderPolicy(); } else { // Normally order is significant in owning sequences; no need to ask each child. propStrategy.ChildOrderPolicy = new SignificantOrderPolicy(); } break; case DataType.ReferenceAtomic: if (classInfo.ClassName == "LexSense" && propertyInfo.PropertyName == "MorphoSyntaxAnalysis") { propStrategy.ContextDescriptorGenerator = new PosContextGenerator(); } propStrategy.NumberOfChildren = NumberOfChildrenAllowed.ZeroOrOne; break; //case DataType.ReferenceCollection: // Nothing special done // break; case DataType.ReferenceSequence: // Trying to merge the Analyses of a segment is problematic. Best to go all-or-nothing, and ensure // we get a conflict report if it fails. if (classInfo.ClassName == "Segment" && propertyInfo.PropertyName == "Analyses") propStrategy.IsAtomic = true; break; // Block of multi-somethings // In model, but nothing special done at the property element level //case DataType.MultiString: // break; //case DataType.MultiUnicode: // break; // Block of other property data types case DataType.Binary: propStrategy.IsAtomic = true; break; case DataType.Boolean: // LT-13320 "Date of Event is lost after send/receive (data loss)" // says these fields don't play nice as immutable. //if (classInfo.ClassName == "CmPerson" || classInfo.ClassName == "RnGenericRec") // propStrategy.IsImmutable = true; // Surely DateOfBirth, DateOfDeath, and DateOfEvent are fixed. onced they happen. :-) propStrategy.NumberOfChildren = NumberOfChildrenAllowed.Zero; break; //case DataType.Float: // Not used in model // break; case DataType.GenDate: // LT-13320 "Date of Event is lost after send/receive (data loss)" // says these fields don't play nice as immutable. //if (classInfo.ClassName == "CmPerson" || classInfo.ClassName == "RnGenericRec") // propStrategy.IsImmutable = true; // Surely DateOfBirth, DateOfDeath, and DateOfEvent are fixed. onced they happen. :-) propStrategy.NumberOfChildren = NumberOfChildrenAllowed.Zero; break; case DataType.Guid: if (classInfo.ClassName == "CmFilter" || classInfo.ClassName == "CmResource") propStrategy.IsImmutable = true; propStrategy.NumberOfChildren = NumberOfChildrenAllowed.Zero; break; case DataType.Integer: // Fall through if (propertyInfo.PropertyName == "HomographNumber") { // Don't fret about conflicts in merging the homograph numbers. propStrategy.AttributesToIgnoreForMerging.Add("val"); } propStrategy.NumberOfChildren = NumberOfChildrenAllowed.Zero; break; //case DataType.Numeric: // Not used in model // break; case DataType.String: // Contains one <Str> element propStrategy.NumberOfChildren = NumberOfChildrenAllowed.ZeroOrOne; break; case DataType.TextPropBinary: propStrategy.ContextDescriptorGenerator = new StyleContextGenerator(); propStrategy.NumberOfChildren = NumberOfChildrenAllowed.ZeroOrOne; break; case DataType.Time: if (propertyInfo.PropertyName == "DateCreated") { propStrategy.IsImmutable = true; } else { // Suppress conflicts and change reports for other date time properties, which currently are all // some variation on modify time, or most recent run time. // For all of them, it is appropriate to just keep the most recent. propStrategy.Premerger = new PreferMostRecentTimePreMerger(); } propStrategy.NumberOfChildren = NumberOfChildrenAllowed.Zero; break; case DataType.Unicode: // Contains one <Uni> element propStrategy.NumberOfChildren = NumberOfChildrenAllowed.ZeroOrOne; break; } strategiesForMerger.SetStrategy( String.Format("{0}{1}_{2}", isCustom ? "Custom_" : "", classInfo.ClassName, propertyInfo.PropertyName), propStrategy); } }
private static bool EnsureBasicValueTypePropertyElementsExist(MetadataCache mdc, FdoClassInfo classInfo, XElement element, IEnumerable <string> basicPropertyNames, out string result) { result = null; if (mdc.ModelVersion < 7000066) { return(true); // The value type data types are only required at DM 7000066, and higher. } foreach (var basicPropertyName in basicPropertyNames) { var currentPropName = basicPropertyName; var isCustomProperty = classInfo.GetProperty(basicPropertyName).IsCustomProperty; var propertyElement = isCustomProperty ? element.Elements("Custom").FirstOrDefault(propElement => propElement.Attribute(SharedConstants.Name).Value == currentPropName) : element.Element(currentPropName); if (propertyElement != null) { continue; } result = string.Format("Required basic property element '{0}' of class '{1}' is missing.", currentPropName, classInfo.ClassName); return(false); } return(true); }
private static bool EnsureBasicValueTypePropertyElementsExist(MetadataCache mdc, FdoClassInfo classInfo, XElement element, IEnumerable<string> basicPropertyNames, out string result) { result = null; if (mdc.ModelVersion < 7000066) return true; // The value type data types are only required at DM 7000066, and higher. foreach (var basicPropertyName in basicPropertyNames) { var currentPropName = basicPropertyName; var isCustomProperty = classInfo.GetProperty(basicPropertyName).IsCustomProperty; var propertyElement = isCustomProperty ? element.Elements("Custom").FirstOrDefault(propElement => propElement.Attribute(SharedConstants.Name).Value == currentPropName) : element.Element(currentPropName); if (propertyElement != null) continue; result = string.Format("Required basic property element '{0}' of class '{1}' is missing.", currentPropName, classInfo.ClassName); return false; } return true; }
private static FdoPropertyInfo GetProperty(FdoClassInfo classInfo, string propertyName) { return((from propInfo in classInfo.AllProperties where propInfo.PropertyName == propertyName select propInfo).FirstOrDefault()); // May be null. }
private static bool GetClassInfoFromElement(MetadataCache mdc, XElement element, out FdoClassInfo classInfo, out string className) { var isOwnSeqNode = element.Name.LocalName == SharedConstants.Ownseq; className = isOwnSeqNode ? element.Attribute(SharedConstants.Class).Value : element.Name.LocalName; classInfo = mdc.GetClassInfo(className); return(isOwnSeqNode); }
private static string ChangeGuids(MetadataCache mdc, FdoClassInfo classInfo, XElement element) { var newGuid = Guid.NewGuid().ToString().ToLowerInvariant(); element.Attribute(SharedConstants.GuidStr).Value = newGuid; // Recurse down through everything that is owned and change those guids. foreach (var owningPropInfo in classInfo.AllOwningProperties) { var isCustomProp = owningPropInfo.IsCustomProperty; var owningPropElement = isCustomProp ? (element.Elements(SharedConstants.Custom).Where(customProp => customProp.Attribute(SharedConstants.Name).Value == owningPropInfo.PropertyName)).FirstOrDefault() : element.Element(owningPropInfo.PropertyName); if (owningPropElement == null || !owningPropElement.HasElements) continue; foreach (var ownedElement in owningPropElement.Elements()) { FdoClassInfo ownedClassInfo; string className; GetClassInfoFromElement(mdc, element, out ownedClassInfo, out className); ChangeGuids(mdc, ownedClassInfo, ownedElement); } } return newGuid; }
private static bool GetClassInfoFromElement(MetadataCache mdc, XElement element, out FdoClassInfo classInfo, out string className) { var isOwnSeqNode = element.Name.LocalName == SharedConstants.Ownseq; className = isOwnSeqNode ? element.Attribute(SharedConstants.Class).Value : element.Name.LocalName; classInfo = mdc.GetClassInfo(className); return isOwnSeqNode; }
private static void AddPropertyStrategiesForClass(MergeStrategies strategiesForMerger, FdoClassInfo classInfo) { foreach (var propertyInfo in classInfo.AllProperties) { var isCustom = propertyInfo.IsCustomProperty; var propStrategy = isCustom ? CreateStrategyForKeyedElement(SharedConstants.Name, false) : CreateSingletonElementStrategy(); switch (propertyInfo.DataType) { // Block of object properties case DataType.OwningAtomic: propStrategy.NumberOfChildren = NumberOfChildrenAllowed.ZeroOrOne; break; //case DataType.OwningCollection: // Nothing special done // break; case DataType.OwningSequence: if ((classInfo.ClassName == "CmPossibilityList" && propertyInfo.PropertyName == "Possibilities") || (propertyInfo.PropertyName == "SubPossibilities" && classInfo.IsOrInheritsFrom("CmPossibility"))) { // Order may or may not be significant in possibility lists and sublists, depending on whether the list is sorted. propStrategy.ChildOrderPolicy = new PossibilityListOrderPolicy(); } else { // Normally order is significant in owning sequences; no need to ask each child. propStrategy.ChildOrderPolicy = new SignificantOrderPolicy(); } break; case DataType.ReferenceAtomic: if (classInfo.ClassName == "LexSense" && propertyInfo.PropertyName == "MorphoSyntaxAnalysis") { propStrategy.ContextDescriptorGenerator = new PosContextGenerator(); } propStrategy.NumberOfChildren = NumberOfChildrenAllowed.ZeroOrOne; break; //case DataType.ReferenceCollection: // Nothing special done // break; case DataType.ReferenceSequence: // Trying to merge the Analyses of a segment is problematic. Best to go all-or-nothing, and ensure // we get a conflict report if it fails. if (classInfo.ClassName == "Segment" && propertyInfo.PropertyName == "Analyses") { propStrategy.IsAtomic = true; } break; // Block of multi-somethings // In model, but nothing special done at the property element level //case DataType.MultiString: // break; //case DataType.MultiUnicode: // break; // Block of other property data types case DataType.Binary: propStrategy.IsAtomic = true; break; case DataType.Boolean: // LT-13320 "Date of Event is lost after send/receive (data loss)" // says these fields don't play nice as immutable. //if (classInfo.ClassName == "CmPerson" || classInfo.ClassName == "RnGenericRec") // propStrategy.IsImmutable = true; // Surely DateOfBirth, DateOfDeath, and DateOfEvent are fixed. onced they happen. :-) propStrategy.NumberOfChildren = NumberOfChildrenAllowed.Zero; break; //case DataType.Float: // Not used in model // break; case DataType.GenDate: // LT-13320 "Date of Event is lost after send/receive (data loss)" // says these fields don't play nice as immutable. //if (classInfo.ClassName == "CmPerson" || classInfo.ClassName == "RnGenericRec") // propStrategy.IsImmutable = true; // Surely DateOfBirth, DateOfDeath, and DateOfEvent are fixed. onced they happen. :-) propStrategy.NumberOfChildren = NumberOfChildrenAllowed.Zero; break; case DataType.Guid: if (classInfo.ClassName == "CmFilter" || classInfo.ClassName == "CmResource") { propStrategy.IsImmutable = true; } propStrategy.NumberOfChildren = NumberOfChildrenAllowed.Zero; break; case DataType.Integer: // Fall through if (propertyInfo.PropertyName == "HomographNumber") { // Don't fret about conflicts in merging the homograph numbers. propStrategy.AttributesToIgnoreForMerging.Add("val"); } propStrategy.NumberOfChildren = NumberOfChildrenAllowed.Zero; break; //case DataType.Numeric: // Not used in model // break; case DataType.String: // Contains one <Str> element propStrategy.NumberOfChildren = NumberOfChildrenAllowed.ZeroOrOne; break; case DataType.TextPropBinary: propStrategy.ContextDescriptorGenerator = new StyleContextGenerator(); propStrategy.NumberOfChildren = NumberOfChildrenAllowed.ZeroOrOne; break; case DataType.Time: if (propertyInfo.PropertyName == "DateCreated") { propStrategy.IsImmutable = true; } else { // Suppress conflicts and change reports for other date time properties, which currently are all // some variation on modify time, or most recent run time. // For all of them, it is appropriate to just keep the most recent. propStrategy.Premerger = new PreferMostRecentTimePreMerger(); } propStrategy.NumberOfChildren = NumberOfChildrenAllowed.Zero; break; case DataType.Unicode: // Contains one <Uni> element propStrategy.NumberOfChildren = NumberOfChildrenAllowed.ZeroOrOne; break; } strategiesForMerger.SetStrategy( String.Format("{0}{1}_{2}", isCustom ? "Custom_" : "", classInfo.ClassName, propertyInfo.PropertyName), propStrategy); } }