diff --git a/ChangeLog.md b/ChangeLog.md index b15e08d..7b22689 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -4,6 +4,21 @@ All notable changes to MIMConfigDocumenter project will be documented in this fi ------------ +### Version 1.17.0610.0 + +#### Changed + +* In the sync engine configuration, Inbound Scoping Filter information is displayed when documenting import attribute flows. +* In the sync engine configuration, sync rule scoping information is printed for join and projection rules. + +#### Fixed + +* In the sync engine configuration, import flows may get duplicated when inbound scoping filter in use. +* In the Sync Rule configuration, Inbound Scoping Filter configuration gets printed in Outbound Scoping Filter section +* In the MIMWAL activity configuration, Query Resources and Value Expressions information gets mixed up. + +------------ + ### Version 1.17.0606.0 #### Fixed diff --git a/src/MIMConfigDocumenter/ConnectorDocumenter.cs b/src/MIMConfigDocumenter/ConnectorDocumenter.cs index 0d26d31..b2ba951 100644 --- a/src/MIMConfigDocumenter/ConnectorDocumenter.cs +++ b/src/MIMConfigDocumenter/ConnectorDocumenter.cs @@ -1460,7 +1460,13 @@ orderby sourceObjectType } else if (joinRuleType.Equals("sync-rule", StringComparison.OrdinalIgnoreCase)) { - mappingType = "Sync Rule - Direct"; + var scopeExpression = string.Empty; + foreach (var scope in joinCriterion.XPathSelectElements("scoping/scope")) + { + scopeExpression += string.Format(CultureInfo.InvariantCulture, "{0} {1} {2} AND ", (string)scope.Element("csAttribute"), (string)scope.Element("csOperator"), (string)scope.Element("csValue")); + } + + mappingType = string.IsNullOrEmpty(scopeExpression) ? "Sync Rule - Direct" : "Sync Rule - Scoped - " + scopeExpression.Substring(0, scopeExpression.Length - " AND ".Length); } Documenter.AddRow(table2, new object[] { sourceObjectType, mappingGroupIndex, metaverseObjectType, sourceAttribute, mappingType, metaverseAttribute }); @@ -1542,7 +1548,7 @@ protected void ProcessConnectorProjectionRules() { Logger.Instance.WriteInfo("Processing Connector Projection Rules."); - this.CreateSimpleSettingsDataSets(3); // 1 = Data Source Object, 2 = Projection Type, 3 = Metaverse Object + this.CreateSimpleOrderedSettingsDataSets(4, true); // 1 = Order Control, 2 = Data Source Object, 3 = Projection Type, 4 = Metaverse Object this.FillConnectorProjectionRulesDataSet(true); this.FillConnectorProjectionRulesDataSet(false); @@ -1586,16 +1592,37 @@ orderby sourceObjectType return; } + var projectionRuleIndex = 0; // This will be the relative rule number if there are more than one sync rule based projection rules. + var previoussourceObjectType = string.Empty; foreach (var projectionRule in projectionRules) { var sourceObjectType = (string)projectionRule.Attribute("cd-object-type"); + + projectionRuleIndex = sourceObjectType == previoussourceObjectType ? projectionRuleIndex + 1 : 0; + previoussourceObjectType = sourceObjectType; + var projectionType = (string)projectionRule.Attribute("type") ?? string.Empty; + var scopeExpression = string.Empty; + if (projectionType.Equals("sync-rule", StringComparison.OrdinalIgnoreCase)) + { + foreach (var scope in projectionRule.XPathSelectElements("scoping/scope")) + { + scopeExpression += string.Format(CultureInfo.InvariantCulture, "{0} {1} {2} AND ", (string)scope.Element("csAttribute"), (string)scope.Element("csOperator"), (string)scope.Element("csValue")); + } + + if (scopeExpression.Length > 5) + { + scopeExpression = scopeExpression.Substring(0, scopeExpression.Length - " AND ".Length); + } + } + projectionType = projectionType.Equals("scripted", StringComparison.OrdinalIgnoreCase) ? "Rules Extension" : projectionType.Equals("declared", StringComparison.OrdinalIgnoreCase) ? - "Declared" : projectionType.Equals("sync-rule", StringComparison.OrdinalIgnoreCase) ? "Sync Rule" : projectionType; + "Declared" : projectionType.Equals("sync-rule", StringComparison.OrdinalIgnoreCase) ? string.IsNullOrEmpty(scopeExpression) ? "Sync Rule - Direct" : "Sync Rule - Scoped - " + scopeExpression : projectionType; + var metaverseObjectType = (string)projectionRule.Element("mv-object-type") ?? string.Empty; - Documenter.AddRow(table, new object[] { sourceObjectType, projectionType, metaverseObjectType }); + Documenter.AddRow(table, new object[] { sourceObjectType + projectionRuleIndex, sourceObjectType, projectionType, metaverseObjectType }); } table.AcceptChanges(); @@ -1768,7 +1795,7 @@ protected void ProcessConnectorObjectTypeImportAttributeFlows() { Logger.Instance.WriteInfo("Processing Connector Import Attribute Flows. This may take a few minutes..."); - this.CreateSimpleOrderedSettingsDataSets(6, true); // / 1 = Order Control, 2 = Data Source Attribute, 3 = To, 4 = Metaverse Attribute, 5 = Mapping Type, 6 = Precedence Order + this.CreateSimpleOrderedSettingsDataSets(7, true); // 1 = Order Control, 2 = Data Source Attribute, 3 = To, 4 = Metaverse Attribute, 5 = Mapping Type, 6 = Scoping Filter, 7 = Precedence Order this.FillConnectorObjectTypeImportAttributeFlowsDataSet(true); this.FillConnectorObjectTypeImportAttributeFlowsDataSet(false); @@ -1815,9 +1842,9 @@ orderby metaverseAttribute return; } - var importFlowRuleIndex = 0; // This will be the relative rule number if there are more than one outbound sync rule import flows for the same metaverse attribute. + var importFlowRuleIndex = 0; // This will be the relative rule number if there are more than one inbound sync rule import flows for the same metaverse attribute. var previousMetaverseAttribute = string.Empty; - foreach (var metaverseAttribute in metaverseAttributes) + foreach (var metaverseAttribute in metaverseAttributes.Distinct()) { var allImportFlowsXPath = "//mv-data/import-attribute-flow/import-flow-set[@mv-object-type = '" + this.currentMetaverseObjectType + "']/import-flows[@mv-attribute = '" + metaverseAttribute + "']"; var precedenceType = config.XPathSelectElement(allImportFlowsXPath) != null ? (string)config.XPathSelectElement(allImportFlowsXPath).Attribute("type") : string.Empty; @@ -1841,6 +1868,7 @@ orderby metaverseAttribute var dataSourceAttribute = string.Empty; var mappingType = string.Empty; + var scopeExpression = string.Empty; if (importFlow.XPathSelectElement("direct-mapping/src-attribute") != null) { @@ -1890,9 +1918,21 @@ orderby metaverseAttribute dataSourceAttribute = !string.IsNullOrEmpty(dataSourceAttribute) ? dataSourceAttribute.Substring(0, dataSourceAttribute.Length - "
".Length) : dataSourceAttribute; mappingType = "Sync Rule - Expression"; // TODO: Print the Sync Rule Expression } + + var syncRuleId = (string)importFlow.XPathSelectElement("sync-rule-mapping").Attribute("sync-rule-id") ?? string.Empty; + + foreach (var scope in connector.XPathSelectElements("join/join-profile/join-criterion[@sync-rule-id='" + syncRuleId + "']/scoping/scope")) + { + scopeExpression += string.Format(CultureInfo.InvariantCulture, "{0} {1} {2} AND ", (string)scope.Element("csAttribute"), (string)scope.Element("csOperator"), (string)scope.Element("csValue")); + } + + if (scopeExpression.Length > 5) + { + scopeExpression = scopeExpression.Substring(0, scopeExpression.Length - " AND ".Length); + } } - Documenter.AddRow(table, new object[] { metaverseAttribute + importFlowRuleIndex, dataSourceAttribute, "→", metaverseAttribute, mappingType, precedenceType.Equals("ranked", StringComparison.OrdinalIgnoreCase) ? importFlowRank.ToString(CultureInfo.InvariantCulture) : precedenceType }); + Documenter.AddRow(table, new object[] { metaverseAttribute + importFlowRuleIndex, dataSourceAttribute, "→", metaverseAttribute, mappingType, scopeExpression, precedenceType.Equals("ranked", StringComparison.OrdinalIgnoreCase) ? importFlowRank.ToString(CultureInfo.InvariantCulture) : precedenceType }); } } @@ -1916,9 +1956,9 @@ protected void PrintConnectorObjectTypeImportAttributeFlows() { if (this.DiffgramDataSet.Tables[0].Rows.Count != 0) { - var headerTable = Documenter.GetSimpleSettingsHeaderTable(new OrderedDictionary { { "Data Source Attribute", 40 }, { "To", 5 }, { "Metaverse Attribute", 20 }, { "Mapping Type", 25 }, { "Precedence Order", 10 } }); + var headerTable = Documenter.GetSimpleSettingsHeaderTable(new OrderedDictionary { { "Data Source Attribute", 30 }, { "To", 5 }, { "Metaverse Attribute", 15 }, { "Mapping Type", 20 }, { "Scoping Filter", 23 }, { "Precedence Order", 7 } }); - this.WriteTable(this.DiffgramDataSet.Tables[0], headerTable); + this.WriteTable(this.DiffgramDataSet.Tables[0], headerTable, HtmlTableSize.Huge); this.WriteBreakTag(); } @@ -2080,9 +2120,9 @@ protected void PrintConnectorObjectTypeExportAttributeFlows() { if (this.DiffgramDataSet.Tables[0].Rows.Count != 0) { - var headerTable = Documenter.GetSimpleSettingsHeaderTable(new OrderedDictionary { { "Data Source Attribute", 20 }, { "From", 5 }, { "Metaverse Attribute", 35 }, { "Mapping Type", 25 }, { "Allow Null", 5 }, { "Initial Flow Only", 10 } }); + var headerTable = Documenter.GetSimpleSettingsHeaderTable(new OrderedDictionary { { "Data Source Attribute", 20 }, { "From", 5 }, { "Metaverse Attribute", 35 }, { "Mapping Type", 26 }, { "Allow Null", 7 }, { "Initial Flow Only", 7 } }); - this.WriteTable(this.DiffgramDataSet.Tables[0], headerTable); + this.WriteTable(this.DiffgramDataSet.Tables[0], headerTable, HtmlTableSize.Huge); } } finally diff --git a/src/MIMConfigDocumenter/MIMServicePolicyDocumenter.cs b/src/MIMConfigDocumenter/MIMServicePolicyDocumenter.cs index 7e69e46..6e98a22 100644 --- a/src/MIMConfigDocumenter/MIMServicePolicyDocumenter.cs +++ b/src/MIMConfigDocumenter/MIMServicePolicyDocumenter.cs @@ -458,7 +458,7 @@ protected string GetFilterText(string filter) var xmlFilter = XElement.Parse(filter); filter = xmlFilter.Value; } - catch (Exception e) + catch (XmlException e) { var info = string.Format(CultureInfo.InvariantCulture, "Unable to Parse Filter '{0}'. Error {1}.", filter, e.ToString()); Logger.Instance.WriteInfo(info); @@ -1216,7 +1216,6 @@ protected void FillWorkflowsSummaryDiffgramDataSet() try { var diffgramTable = this.DiffgramDataSet.Tables[0]; - var diffgramTable2 = this.DiffgramDataSet.Tables[1]; var objectType = "WorkflowDefinition"; @@ -1333,7 +1332,7 @@ protected void ProcessWorkflow() new KeyValuePair("Workflow Type", "RequestPhase"), new KeyValuePair("Run On Policy Update", "RunOnPolicyUpdate"), }); - this.PrintSimpleSettingsSectionTable(new OrderedDictionary { { "General", 30 }, { string.Empty, 70 } }); + this.PrintSimpleSettingsSectionTable(new OrderedDictionary { { "General", 30 }, { string.Empty, 70 } }, HtmlTableSize.Large); // Workflow Activties this.CreateWorkflowActivityDetailsDataSets(); @@ -1644,9 +1643,9 @@ protected void FillWorkflowActivityValueExpressions(DataTable activityValueExpre for (var expressionIndex = 0; expressionIndex < hashtableKeyCount; ++expressionIndex) { - var valueExpression = ((IEnumerable)hashtable.XPathEvaluate("//Key[String = '" + expressionIndex + ":0']/parent::node()/text()")).Cast().FirstOrDefault(); - var target = ((IEnumerable)hashtable.XPathEvaluate("//Key[String = '" + expressionIndex + ":1']/parent::node()/text()")).Cast().FirstOrDefault(); - var allowNull = ((IEnumerable)hashtable.XPathEvaluate("//Key[String = '" + expressionIndex + ":2']/parent::node()/text()")).Cast().FirstOrDefault(); + var valueExpression = ((IEnumerable)hashtable.XPathEvaluate(".//Key[String = '" + expressionIndex + ":0']/parent::node()/text()")).Cast().FirstOrDefault(); + var target = ((IEnumerable)hashtable.XPathEvaluate(".//Key[String = '" + expressionIndex + ":1']/parent::node()/text()")).Cast().FirstOrDefault(); + var allowNull = ((IEnumerable)hashtable.XPathEvaluate(".//Key[String = '" + expressionIndex + ":2']/parent::node()/text()")).Cast().FirstOrDefault(); if (activityValueExpressionsTable.Columns.Count == 4) { @@ -1908,7 +1907,7 @@ protected void PrintWorkflowAssemblyVersion(int activityIndex) #region table this.ReportWriter.WriteBeginTag("table"); - this.ReportWriter.WriteAttribute("class", HtmlTableSize.Standard.ToString() + " " + this.GetCssVisibilityClass()); + this.ReportWriter.WriteAttribute("class", HtmlTableSize.Large.ToString() + " " + this.GetCssVisibilityClass()); this.ReportWriter.Write(HtmlTextWriter.TagRightChar); { this.WriteTableHeader(headerTable); @@ -1958,7 +1957,7 @@ protected void PrintWorkflowSelectedOptions(int activityIndex) #region table this.ReportWriter.WriteBeginTag("table"); - this.ReportWriter.WriteAttribute("class", HtmlTableSize.Standard.ToString() + " " + this.GetCssVisibilityClass()); + this.ReportWriter.WriteAttribute("class", HtmlTableSize.Large.ToString() + " " + this.GetCssVisibilityClass()); this.ReportWriter.Write(HtmlTextWriter.TagRightChar); { this.WriteTableHeader(headerTable); @@ -2009,7 +2008,7 @@ protected void PrintWorkflowActivityMultiValuesTable(int activityIndex, OrderedD #region table this.ReportWriter.WriteBeginTag("table"); - this.ReportWriter.WriteAttribute("class", HtmlTableSize.Standard.ToString() + " " + this.GetCssVisibilityClass()); + this.ReportWriter.WriteAttribute("class", HtmlTableSize.Large.ToString() + " " + this.GetCssVisibilityClass()); this.ReportWriter.Write(HtmlTextWriter.TagRightChar); { this.WriteTableHeader(headerTable); @@ -2066,7 +2065,7 @@ protected void PrintWorkflowActivityValueExpressionsTable(int activityIndex, int #region table this.ReportWriter.WriteBeginTag("table"); - this.ReportWriter.WriteAttribute("class", HtmlTableSize.Standard.ToString() + " " + this.GetCssVisibilityClass()); + this.ReportWriter.WriteAttribute("class", HtmlTableSize.Large.ToString() + " " + this.GetCssVisibilityClass()); this.ReportWriter.Write(HtmlTextWriter.TagRightChar); { this.WriteTableHeader(headerTable); @@ -2109,7 +2108,7 @@ protected void PrintWorkflowActivityUnhandledWarning(string activityType) Logger.Instance.WriteWarning(warning); this.ReportWriter.WriteBeginTag("table"); - this.ReportWriter.WriteAttribute("class", HtmlTableSize.Standard.ToString()); + this.ReportWriter.WriteAttribute("class", HtmlTableSize.Large.ToString()); this.ReportWriter.Write(HtmlTextWriter.TagRightChar); this.ReportWriter.WriteFullBeginTag("tr"); this.ReportWriter.WriteBeginTag("td"); @@ -2285,11 +2284,11 @@ protected void ProcessSynchronizationRule() // Outbound System Scoping Filter var outboundScopingFiltersChange = this.GetAttributeChange("msidmOutboundScopingFilters"); - this.ProcessSynchronizationRuleSystemScopingFilter(outboundScopingFiltersChange); + this.ProcessSynchronizationRuleSystemScopingFilter(outboundScopingFiltersChange, true); // Inbound System Scoping Filter var inboundScopingFiltersChange = this.GetAttributeChange("ConnectedSystemScope"); - this.ProcessSynchronizationRuleSystemScopingFilter(inboundScopingFiltersChange); + this.ProcessSynchronizationRuleSystemScopingFilter(inboundScopingFiltersChange, false); // Relationship var headerTable = Documenter.GetSimpleSettingsHeaderTable(new OrderedDictionary { { "Relationship", 100 } }); @@ -2384,7 +2383,8 @@ protected void FillSynchronizationRuleGeneralInfoDiffgramDataSet() /// Processes the Synchronization Rule Inbound / Outbound System Scoping Filters /// /// The inbound / outbound system scoping filter attribute change. - protected void ProcessSynchronizationRuleSystemScopingFilter(AttributeChange systemScopingFiltersChange) + /// if set to true, denotes outbound system scoping filter. Otherwise, the . + protected void ProcessSynchronizationRuleSystemScopingFilter(AttributeChange systemScopingFiltersChange, bool outboundSystemScopingFilters) { if (systemScopingFiltersChange == null) { @@ -2395,7 +2395,7 @@ protected void ProcessSynchronizationRuleSystemScopingFilter(AttributeChange sys this.FillSynchronizationRuleSystemScopingFiltersDataSet(systemScopingFiltersChange.NewValue, true); this.FillSynchronizationRuleSystemScopingFiltersDataSet(systemScopingFiltersChange.OldValue, false); this.CreateSimpleOrderedSettingsDiffgram(); - this.PrintSynchronizationRuleSystemScopingFilters(true); + this.PrintSynchronizationRuleSystemScopingFilters(outboundSystemScopingFilters); } /// @@ -2721,12 +2721,17 @@ protected void FillSynchronizationRuleOutboundTransformationsDataSet(AttributeCh { foreach (var valueChange in transformationsChange.AttributeValues) { - var exportFlowXml = pilotConfig ? valueChange.NewValue : valueChange.OldValue; + var exportFlowXml = pilotConfig ? (valueChange.ValueModificationType != DataRowState.Deleted ? valueChange.NewValue : string.Empty) : valueChange.OldValue; // Deleted values should be processed only when it's production config. if (!string.IsNullOrEmpty(exportFlowXml)) { try { var exportFlow = XElement.Parse(exportFlowXml); + if (!exportFlow.Name.LocalName.Equals("export-flow", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + var destination = (string)exportFlow.Element("dest"); var initialFlow = transformationsChange.AttributeName.Equals("InitialFlow", StringComparison.OrdinalIgnoreCase) ? true : false; var existenceTest = transformationsChange.AttributeName.Equals("ExistenceTest", StringComparison.OrdinalIgnoreCase) ? true : false; @@ -2822,12 +2827,17 @@ protected void FillSynchronizationRuleInboundTransformationsDataSet(AttributeCha { foreach (var valueChange in transformationsChange.AttributeValues) { - var importFlowXml = pilotConfig ? valueChange.NewValue : valueChange.OldValue; + var importFlowXml = pilotConfig ? (valueChange.ValueModificationType != DataRowState.Deleted ? valueChange.NewValue : string.Empty) : valueChange.OldValue; // Deleted values should be processed only when it's production config. if (!string.IsNullOrEmpty(importFlowXml)) { try { var importFlow = XElement.Parse(importFlowXml); + if (!importFlow.Name.LocalName.Equals("import-flow", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + var destination = (string)importFlow.Element("dest"); var directFlow = importFlow.Elements("fn").Count() == 0; var source = string.Empty; @@ -3045,7 +3055,7 @@ protected void FillObjectVisualizationConfigurationsSummaryDiffgramDataSet() var description = descriptionChange.NewValue; var descriptionOld = descriptionChange.OldValue; - Documenter.AddRow(diffgramTable, new object[] { displayName, displayName, targetObjectType, appliesToCreate, appliesToEdit, appliesToView, configurationData, description, objectModificationType, displayName, targetObjectTypeOld, appliesToCreateOld, appliesToEditOld, appliesToViewOld, configurationDataOld, description }); + Documenter.AddRow(diffgramTable, new object[] { displayName, displayName, targetObjectType, appliesToCreate, appliesToEdit, appliesToView, configurationData, description, objectModificationType, displayName, targetObjectTypeOld, appliesToCreateOld, appliesToEditOld, appliesToViewOld, configurationDataOld, descriptionOld }); } this.DiffgramDataSet = Documenter.SortDataSet(this.DiffgramDataSet); diff --git a/src/MIMConfigDocumenter/MetaverseDocumenter.cs b/src/MIMConfigDocumenter/MetaverseDocumenter.cs index 02115a8..322efa1 100644 --- a/src/MIMConfigDocumenter/MetaverseDocumenter.cs +++ b/src/MIMConfigDocumenter/MetaverseDocumenter.cs @@ -223,7 +223,8 @@ private void CreateMetaverseObjectTypeDataSets() var column52 = new DataColumn("SourceObjectType"); var column62 = new DataColumn("SourceAttribute"); var column72 = new DataColumn("MappingType"); - var column82 = new DataColumn("ConnectorGuid"); + var column82 = new DataColumn("Inbound Scoping Filter"); + var column92 = new DataColumn("ConnectorGuid"); table2.Columns.Add(column12); table2.Columns.Add(column22); @@ -233,7 +234,8 @@ private void CreateMetaverseObjectTypeDataSets() table2.Columns.Add(column62); table2.Columns.Add(column72); table2.Columns.Add(column82); - table2.PrimaryKey = new[] { column12, column42, column52, column62, column72 }; + table2.Columns.Add(column92); + table2.PrimaryKey = new[] { column12, column42, column52, column62, column72, column82 }; this.PilotDataSet = new DataSet("MetaverseObjectType") { Locale = CultureInfo.InvariantCulture }; this.PilotDataSet.Tables.Add(table); @@ -291,7 +293,7 @@ private DataTable GetMetaverseObjectTypePrintTable() printTable.Rows.Add((new OrderedDictionary { { "TableIndex", 1 }, { "ColumnIndex", 2 }, { "Hidden", false }, { "SortOrder", -1 }, { "BookmarkIndex", -1 }, { "JumpToBookmarkIndex", -1 }, { "ChangeIgnored", false } }).Values.Cast().ToArray()); // Connector - printTable.Rows.Add((new OrderedDictionary { { "TableIndex", 1 }, { "ColumnIndex", 3 }, { "Hidden", false }, { "SortOrder", -1 }, { "BookmarkIndex", -1 }, { "JumpToBookmarkIndex", 7 }, { "ChangeIgnored", false } }).Values.Cast().ToArray()); + printTable.Rows.Add((new OrderedDictionary { { "TableIndex", 1 }, { "ColumnIndex", 3 }, { "Hidden", false }, { "SortOrder", -1 }, { "BookmarkIndex", -1 }, { "JumpToBookmarkIndex", 8 }, { "ChangeIgnored", false } }).Values.Cast().ToArray()); // Data Source Object Type printTable.Rows.Add((new OrderedDictionary { { "TableIndex", 1 }, { "ColumnIndex", 4 }, { "Hidden", false }, { "SortOrder", -1 }, { "BookmarkIndex", -1 }, { "JumpToBookmarkIndex", -1 }, { "ChangeIgnored", false } }).Values.Cast().ToArray()); @@ -302,8 +304,11 @@ private DataTable GetMetaverseObjectTypePrintTable() // Mapping Type printTable.Rows.Add((new OrderedDictionary { { "TableIndex", 1 }, { "ColumnIndex", 6 }, { "Hidden", false }, { "SortOrder", -1 }, { "BookmarkIndex", -1 }, { "JumpToBookmarkIndex", -1 }, { "ChangeIgnored", false } }).Values.Cast().ToArray()); + // Inbound Scoping Filter + printTable.Rows.Add((new OrderedDictionary { { "TableIndex", 1 }, { "ColumnIndex", 7 }, { "Hidden", false }, { "SortOrder", -1 }, { "BookmarkIndex", -1 }, { "JumpToBookmarkIndex", -1 }, { "ChangeIgnored", false } }).Values.Cast().ToArray()); + // ConnectorGuid - printTable.Rows.Add((new OrderedDictionary { { "TableIndex", 1 }, { "ColumnIndex", 7 }, { "Hidden", true }, { "SortOrder", -1 }, { "BookmarkIndex", -1 }, { "JumpToBookmarkIndex", -1 }, { "ChangeIgnored", true } }).Values.Cast().ToArray()); + printTable.Rows.Add((new OrderedDictionary { { "TableIndex", 1 }, { "ColumnIndex", 8 }, { "Hidden", true }, { "SortOrder", -1 }, { "BookmarkIndex", -1 }, { "JumpToBookmarkIndex", -1 }, { "ChangeIgnored", true } }).Values.Cast().ToArray()); printTable.AcceptChanges(); @@ -395,6 +400,7 @@ orderby name Logger.Instance.WriteVerbose("Processing Sync Rule Info for Connector: '{0}'.", connectorName); + var scopeExpression = string.Empty; if (importFlow.XPathSelectElement("direct-mapping") != null) { row2[5] = (string)importFlow.XPathSelectElement("direct-mapping/src-attribute"); @@ -445,9 +451,24 @@ orderby name row2[5] = dataSourceAttribute.TrimEnd(','); row2[6] = "Sync Rule - Expression"; // TODO: Print the Sync Rule Expression } + + var syncRuleId = (string)importFlow.XPathSelectElement("sync-rule-mapping").Attribute("sync-rule-id") ?? string.Empty; + + var connector = config.XPathSelectElement("//ma-data[id ='" + connectorId + "']"); + + foreach (var scope in connector.XPathSelectElements("join/join-profile/join-criterion[@sync-rule-id='" + syncRuleId + "']/scoping/scope")) + { + scopeExpression += string.Format(CultureInfo.InvariantCulture, "{0} {1} {2} AND ", (string)scope.Element("csAttribute"), (string)scope.Element("csOperator"), (string)scope.Element("csValue")); + } + + if (scopeExpression.Length > 5) + { + scopeExpression = scopeExpression.Substring(0, scopeExpression.Length - " AND ".Length); + } } - row2[7] = connectorId; + row2[7] = scopeExpression; + row2[8] = connectorId; Documenter.AddRow(table2, row2); Logger.Instance.WriteVerbose("Processed Sync Rule Info for Connector: '{0}'.", connectorName); @@ -510,23 +531,26 @@ private DataTable GetMetaverseObjectTypeHeaderTable() headerTable.Rows.Add((new OrderedDictionary { { "RowIndex", 0 }, { "ColumnIndex", 3 }, { "ColumnName", "Indexed" }, { "RowSpan", 2 }, { "ColSpan", 1 }, { "ColWidth", 5 } }).Values.Cast().ToArray()); // Precedence - headerTable.Rows.Add((new OrderedDictionary { { "RowIndex", 0 }, { "ColumnIndex", 4 }, { "ColumnName", "Precedence" }, { "RowSpan", 1 }, { "ColSpan", 5 }, { "ColWidth", 0 } }).Values.Cast().ToArray()); + headerTable.Rows.Add((new OrderedDictionary { { "RowIndex", 0 }, { "ColumnIndex", 4 }, { "ColumnName", "Precedence" }, { "RowSpan", 1 }, { "ColSpan", 6 }, { "ColWidth", 0 } }).Values.Cast().ToArray()); // Header Row 2 // Precedence Display - Rank or Manual or Equal headerTable.Rows.Add((new OrderedDictionary { { "RowIndex", 1 }, { "ColumnIndex", 0 }, { "ColumnName", "Rank" }, { "RowSpan", 1 }, { "ColSpan", 1 }, { "ColWidth", 5 } }).Values.Cast().ToArray()); // Connector - headerTable.Rows.Add((new OrderedDictionary { { "RowIndex", 1 }, { "ColumnIndex", 1 }, { "ColumnName", "Management Agent" }, { "RowSpan", 1 }, { "ColSpan", 1 }, { "ColWidth", 15 } }).Values.Cast().ToArray()); + headerTable.Rows.Add((new OrderedDictionary { { "RowIndex", 1 }, { "ColumnIndex", 1 }, { "ColumnName", "Management Agent" }, { "RowSpan", 1 }, { "ColSpan", 1 }, { "ColWidth", 13 } }).Values.Cast().ToArray()); // Data Source Object Type - headerTable.Rows.Add((new OrderedDictionary { { "RowIndex", 1 }, { "ColumnIndex", 2 }, { "ColumnName", "Data Source Object Type" }, { "RowSpan", 1 }, { "ColSpan", 1 }, { "ColWidth", 10 } }).Values.Cast().ToArray()); + headerTable.Rows.Add((new OrderedDictionary { { "RowIndex", 1 }, { "ColumnIndex", 2 }, { "ColumnName", "Data Source Object Type" }, { "RowSpan", 1 }, { "ColSpan", 1 }, { "ColWidth", 7 } }).Values.Cast().ToArray()); // Data Source Attribute - headerTable.Rows.Add((new OrderedDictionary { { "RowIndex", 1 }, { "ColumnIndex", 3 }, { "ColumnName", "Data Source Attribute" }, { "RowSpan", 1 }, { "ColSpan", 1 }, { "ColWidth", 20 } }).Values.Cast().ToArray()); + headerTable.Rows.Add((new OrderedDictionary { { "RowIndex", 1 }, { "ColumnIndex", 3 }, { "ColumnName", "Data Source Attribute" }, { "RowSpan", 1 }, { "ColSpan", 1 }, { "ColWidth", 15 } }).Values.Cast().ToArray()); // Mapping Type - headerTable.Rows.Add((new OrderedDictionary { { "RowIndex", 1 }, { "ColumnIndex", 4 }, { "ColumnName", "Mapping Type" }, { "RowSpan", 1 }, { "ColSpan", 1 }, { "ColWidth", 20 } }).Values.Cast().ToArray()); + headerTable.Rows.Add((new OrderedDictionary { { "RowIndex", 1 }, { "ColumnIndex", 4 }, { "ColumnName", "Mapping Type" }, { "RowSpan", 1 }, { "ColSpan", 1 }, { "ColWidth", 15 } }).Values.Cast().ToArray()); + + // Inbound Scoping Filter + headerTable.Rows.Add((new OrderedDictionary { { "RowIndex", 1 }, { "ColumnIndex", 5 }, { "ColumnName", "Inbound Scoping Filter" }, { "RowSpan", 1 }, { "ColSpan", 1 }, { "ColWidth", 15 } }).Values.Cast().ToArray()); headerTable.AcceptChanges(); diff --git a/src/MIMConfigDocumenter/ServiceCommonDocumenter.cs b/src/MIMConfigDocumenter/ServiceCommonDocumenter.cs index a65345d..aba4399 100644 --- a/src/MIMConfigDocumenter/ServiceCommonDocumenter.cs +++ b/src/MIMConfigDocumenter/ServiceCommonDocumenter.cs @@ -1360,7 +1360,8 @@ protected void PrintSimpleSectionHeader(int level) /// Prints simple settings section table /// /// The table header column names - protected void PrintSimpleSettingsSectionTable(OrderedDictionary columnNames) + /// The size (width) of the HTML table + protected void PrintSimpleSettingsSectionTable(OrderedDictionary columnNames, HtmlTableSize tableSize = HtmlTableSize.Standard) { Logger.Instance.WriteMethodEntry(); @@ -1369,7 +1370,7 @@ protected void PrintSimpleSettingsSectionTable(OrderedDictionary columnNames) if (this.DiffgramDataSet.Tables[0].Rows.Count != 0) { var headerTable = columnNames == null || columnNames.Count == 0 ? null : Documenter.GetSimpleSettingsHeaderTable(columnNames); - this.WriteTable(this.DiffgramDataSet.Tables[0], headerTable); + this.WriteTable(this.DiffgramDataSet.Tables[0], headerTable, tableSize); } } finally diff --git a/src/VersionInfo.cs b/src/VersionInfo.cs index 08695be..7c21181 100644 --- a/src/VersionInfo.cs +++ b/src/VersionInfo.cs @@ -22,7 +22,7 @@ internal static class VersionInfo /// Build Number (MMDD) /// Revision (if any on the same day) /// - internal const string Version = "1.17.0609.0"; + internal const string Version = "1.17.0610.0"; /// /// File Version information for the assembly consists of the following four values: @@ -31,6 +31,6 @@ internal static class VersionInfo /// Build Number (MMDD) /// Revision (if any on the same day) /// - internal const string FileVersion = "1.17.0609.0"; + internal const string FileVersion = "1.17.0610.0"; } } \ No newline at end of file