Skip to content

Commit facc593

Browse files
committed
DomainConfigurationParsers
for json and for xml formats
1 parent 551d6c2 commit facc593

1 file changed

Lines changed: 334 additions & 0 deletions

File tree

Lines changed: 334 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
1+
// Copyright (C) 2024 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
4+
5+
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using Microsoft.Extensions.Configuration;
10+
using Xtensive.Collections;
11+
using Xtensive.Orm.Configuration.Options;
12+
13+
namespace Xtensive.Orm.Configuration.Internals
14+
{
15+
internal interface IConfigurationSectionParser
16+
{
17+
DomainConfiguration Parse(IConfiguration configuration);
18+
19+
DomainConfiguration Parse(IConfigurationRoot configuration, string sectionName);
20+
21+
DomainConfiguration Parse(IConfigurationSection domainConfiguration, Dictionary<string, string> connectionStrings = null);
22+
23+
}
24+
25+
internal sealed class XmlDomainConfigParser : DomainConfigurationParser
26+
{
27+
28+
protected override void ProcessNamingConvention(IConfigurationSection namingConventionSection, DomainConfigurationOptions domainConfiguratonOptions)
29+
{
30+
if (namingConventionSection == null) {
31+
domainConfiguratonOptions.NamingConventionRaw = null;
32+
return;
33+
}
34+
35+
if (namingConventionSection.GetChildren().Any()) {
36+
var namingConvetion = namingConventionSection.Get<NamingConventionOptions>();
37+
if (namingConvetion!= null) {
38+
var synonymsSection = namingConventionSection.GetSection(NamespaceSynonymSectionName);
39+
var synonyms = synonymsSection != null && synonymsSection.GetChildren().Any()
40+
? GetSelfOrChildren(synonymsSection.GetSection(SynonymElementName))
41+
.Select(s => s.Get<NamespaceSynonymOptions>())
42+
.Where(ns => ns != null)
43+
.ToArray()
44+
: Array.Empty<NamespaceSynonymOptions>();
45+
46+
namingConvetion.NamespaceSynonyms = synonyms;
47+
domainConfiguratonOptions.NamingConventionRaw = namingConvetion;
48+
}
49+
else {
50+
domainConfiguratonOptions.NamingConventionRaw = null;
51+
}
52+
}
53+
}
54+
55+
protected override void ProcessVersioningConvention(IConfigurationSection versioningConventionSection, DomainConfigurationOptions domainConfiguratonOptions)
56+
{
57+
if (versioningConventionSection == null) {
58+
domainConfiguratonOptions.VersioningConvention = null;
59+
return;
60+
}
61+
62+
if (versioningConventionSection.GetChildren().Any()) {
63+
var versioningConvention = versioningConventionSection.Get<VersioningConventionOptions>();
64+
65+
domainConfiguratonOptions.VersioningConvention = versioningConvention != null
66+
? versioningConvention
67+
: null;
68+
}
69+
}
70+
71+
protected override void ProcessTypes(IConfigurationSection typesSection, DomainConfigurationOptions domainConfigurationOptions)
72+
{
73+
if (typesSection == null) {
74+
domainConfigurationOptions.Types = Array.Empty<TypeRegistrationOptions>();
75+
return;
76+
}
77+
if (TryProcessTypeRegistrationsWithAttributes(typesSection, domainConfigurationOptions)
78+
|| TryProcessTypeRegistrationsWithNodes(typesSection, domainConfigurationOptions))
79+
return;
80+
domainConfigurationOptions.Types = Array.Empty<TypeRegistrationOptions>();
81+
}
82+
83+
private bool TryProcessTypeRegistrationsWithAttributes(IConfigurationSection typesSection,
84+
DomainConfigurationOptions domainConfigurationOptions)
85+
{
86+
var registrations = typesSection.GetSection(OldStyleTypeRegistrationElementName);
87+
if (registrations != null && registrations.GetChildren().Any()) {
88+
domainConfigurationOptions.Types = GetSelfOrChildren(registrations)
89+
.Select(s => s.Get<TypeRegistrationOptions>())
90+
.Where(tr => tr != null)
91+
.ToArray();
92+
return true;
93+
}
94+
return false;
95+
}
96+
97+
private bool TryProcessTypeRegistrationsWithNodes(IConfigurationSection typesSection,
98+
DomainConfigurationOptions domainConfigurationOptions)
99+
{
100+
var registrations = typesSection.GetSection(TypeRegistrationElementName);
101+
if (registrations == null)
102+
return false;
103+
104+
domainConfigurationOptions.Types = GetSelfOrChildren(registrations)
105+
.Select(s => s.Get<TypeRegistrationOptions>())
106+
.Where(tr => tr != null)
107+
.ToArray();
108+
return true;
109+
}
110+
111+
protected override void ProcessDatabases(IConfigurationSection databasesSection, DomainConfigurationOptions domainConfiguratonOptions)
112+
{
113+
domainConfiguratonOptions.Databases.Clear();
114+
if (databasesSection == null)
115+
return;
116+
var databaseElement = databasesSection.GetSection(DatabaseElementName);
117+
if (databaseElement == null)
118+
return;
119+
foreach (var section in GetSelfOrChildren(databaseElement, true)) {
120+
var dbItem = section.Get<DatabaseOptions>();
121+
if (dbItem == null)
122+
continue;
123+
domainConfiguratonOptions.Databases.Add(dbItem.Name, dbItem);
124+
}
125+
}
126+
127+
protected override void ProcessKeyGenerators(IConfigurationSection keyGeneratorsSection, DomainConfigurationOptions domainConfiguratonOptions)
128+
{
129+
domainConfiguratonOptions.KeyGenerators.Clear();
130+
ProcessCollectionOfOptions(keyGeneratorsSection, KeyGeneratorElementName, domainConfiguratonOptions.KeyGenerators);
131+
}
132+
133+
protected override void ProcessIgnoreRules(IConfigurationSection ignoreRulesSection, Options.DomainConfigurationOptions domainConfiguratonOptions)
134+
{
135+
domainConfiguratonOptions.IgnoreRules.Clear();
136+
ProcessCollectionOfOptions(ignoreRulesSection, RuleElementName, domainConfiguratonOptions.IgnoreRules);
137+
}
138+
139+
protected override void ProcessMappingRules(IConfigurationSection mappingRulesSection, Options.DomainConfigurationOptions domainConfiguratonOptions)
140+
{
141+
domainConfiguratonOptions.MappingRules.Clear();
142+
ProcessCollectionOfOptions(mappingRulesSection, RuleElementName, domainConfiguratonOptions.MappingRules);
143+
}
144+
145+
protected override void ProcessSessions(IConfigurationSection sessionsSection, Options.DomainConfigurationOptions domainConfiguratonOptions)
146+
{
147+
domainConfiguratonOptions.Sessions.Clear();
148+
if (sessionsSection == null)
149+
return;
150+
var sessionElement = sessionsSection.GetSection(SessionElementName);
151+
if (sessionElement == null)
152+
return;
153+
foreach (var section in GetSelfOrChildren(sessionElement, true)) {
154+
var sessionItem = section.Get<SessionConfigurationOptions>();
155+
if (sessionItem == null)
156+
continue;
157+
domainConfiguratonOptions.Sessions.Add(sessionItem.Name, sessionItem);
158+
}
159+
}
160+
161+
private void ProcessCollectionOfOptions<TOption>(IConfigurationSection collectionSection, string itemKey, OptionsCollection<TOption> collection)
162+
where TOption : class, IIdentifyableOptions
163+
{
164+
if (collectionSection == null)
165+
return;
166+
var collectionElement = collectionSection.GetSection(itemKey);
167+
if (collectionElement == null)
168+
return;
169+
foreach (var item in GetSelfOrChildren(collectionElement)) {
170+
var optItem = item.Get<TOption>();
171+
collection.Add(optItem);
172+
}
173+
}
174+
175+
private IEnumerable<IConfigurationSection> GetSelfOrChildren(IConfigurationSection section, bool requiredName = false)
176+
{
177+
var children = section.GetChildren().ToList();
178+
if (children.Count > 0) {
179+
if (requiredName) {
180+
var anyItemWithName = children.Any(i => i["name"] != null);
181+
if (anyItemWithName) {
182+
return children;
183+
}
184+
}
185+
var firstChild = children[0];
186+
var isIndexed = firstChild.Key == "0";
187+
if (isIndexed)
188+
return children;
189+
else
190+
return EnumerableUtils.One(section);
191+
}
192+
return children;
193+
}
194+
}
195+
196+
internal class FromJsonToDomainConfigurationParser : DomainConfigurationParser
197+
{
198+
199+
protected override void ProcessNamingConvention(IConfigurationSection namingConventionSection, DomainConfigurationOptions domainConfiguratonOptions)
200+
{
201+
if (namingConventionSection == null || !namingConventionSection.GetChildren().Any())
202+
return;
203+
var jsonListVariant = namingConventionSection.Get<NamingConventionOptions>();
204+
if (jsonListVariant.NamespaceSynonyms == null)
205+
jsonListVariant.NamespaceSynonyms = Array.Empty<NamespaceSynonymOptions>();
206+
domainConfiguratonOptions.NamingConventionRaw = jsonListVariant;
207+
}
208+
}
209+
210+
internal abstract class DomainConfigurationParser : IConfigurationSectionParser
211+
{
212+
protected const string RuleElementName = "Rule";
213+
protected const string KeyGeneratorElementName = "KeyGenerator";
214+
protected const string OldStyleTypeRegistrationElementName = "Add";
215+
protected const string TypeRegistrationElementName = "Registration";
216+
protected const string SynonymElementName = "Synonym";
217+
protected const string DatabaseElementName = "Database";
218+
protected const string SessionElementName = "Session";
219+
220+
protected const string NamingConventionSectionName = "NamingConvention";
221+
protected const string VersioningConventionSectionName = "VersioningConvention";
222+
protected const string TypesSectionName = "Types";
223+
protected const string DatabasesSectionName = "Databases";
224+
protected const string KeyGeneratorsSectionName = "KeyGenerators";
225+
protected const string IgnoreRulesSectionName = "IgnoreRules";
226+
protected const string MappingRulesSectionName = "MappingRules";
227+
protected const string SessionsSectionName = "Sessions";
228+
protected const string NamespaceSynonymSectionName = "NamespaceSynonyms";
229+
230+
public DomainConfiguration Parse(IConfiguration configuration)
231+
{
232+
if (configuration is IConfigurationRoot configurationRoot) {
233+
return Parse(configurationRoot, WellKnown.DefaultConfigurationSection);
234+
}
235+
else if (configuration is IConfigurationSection configurationSection) {
236+
return Parse(configurationSection);
237+
}
238+
throw new InvalidOperationException("");
239+
}
240+
241+
public DomainConfiguration Parse(IConfigurationRoot configuration, string sectionName)
242+
{
243+
var context = new ConfigurationParserContext(configuration, sectionName);
244+
return ParseInternal(context);
245+
}
246+
247+
public DomainConfiguration Parse(IConfigurationSection domainConfiguration, Dictionary<string, string> connectionStrings = null)
248+
{
249+
var context = new ConfigurationParserContext(domainConfiguration, connectionStrings);
250+
return ParseInternal(context);
251+
}
252+
253+
private DomainConfiguration ParseInternal(ConfigurationParserContext context)
254+
{
255+
var domainByNameSection = context.CurrentSection;
256+
if (domainByNameSection == null || !domainByNameSection.GetChildren().Any()) {
257+
return null;
258+
}
259+
// this handles only root properties of domain configuration
260+
var domainConfigurationOptions = context.CurrentSection.Get<Options.DomainConfigurationOptions>();
261+
if (domainConfigurationOptions == null) {
262+
return null;
263+
}
264+
265+
// all sub-items require manual reading;
266+
ProcessNamingConvention(domainByNameSection.GetSection(NamingConventionSectionName), domainConfigurationOptions);
267+
ProcessVersioningConvention(domainByNameSection.GetSection(VersioningConventionSectionName), domainConfigurationOptions);
268+
ProcessTypes(domainByNameSection.GetSection(TypesSectionName), domainConfigurationOptions);
269+
ProcessDatabases(domainByNameSection.GetSection(DatabasesSectionName), domainConfigurationOptions);
270+
ProcessKeyGenerators(domainByNameSection.GetSection(KeyGeneratorsSectionName), domainConfigurationOptions);
271+
ProcessIgnoreRules(domainByNameSection.GetSection(IgnoreRulesSectionName), domainConfigurationOptions);
272+
ProcessMappingRules(domainByNameSection.GetSection(MappingRulesSectionName), domainConfigurationOptions);
273+
ProcessSessions(domainByNameSection.GetSection(SessionsSectionName), domainConfigurationOptions);
274+
275+
return domainConfigurationOptions.ToNative(context.ConnectionStrings);
276+
}
277+
278+
protected virtual void ProcessNamingConvention(IConfigurationSection namingConventionSection, DomainConfigurationOptions domainConfiguratonOptions)
279+
{
280+
}
281+
282+
protected virtual void ProcessVersioningConvention(IConfigurationSection versioningConventionSection, DomainConfigurationOptions domainConfiguratonOptions)
283+
{
284+
}
285+
286+
protected virtual void ProcessTypes(IConfigurationSection typesSection, DomainConfigurationOptions domainConfigurationOptions)
287+
{
288+
}
289+
290+
protected virtual void ProcessDatabases(IConfigurationSection databasesSection, DomainConfigurationOptions domainConfiguratonOptions)
291+
{
292+
}
293+
294+
protected virtual void ProcessKeyGenerators(IConfigurationSection keyGeneratorsSection, DomainConfigurationOptions domainConfiguratonOptions)
295+
{
296+
}
297+
298+
protected virtual void ProcessIgnoreRules(IConfigurationSection ignoreRulesSection, DomainConfigurationOptions domainConfiguratonOptions)
299+
{
300+
}
301+
302+
protected virtual void ProcessMappingRules(IConfigurationSection mappingRulesSection, DomainConfigurationOptions domainConfiguratonOptions)
303+
{
304+
}
305+
306+
protected virtual void ProcessSessions(IConfigurationSection sessionsSection, DomainConfigurationOptions domainConfiguratonOptions)
307+
{
308+
}
309+
}
310+
311+
internal sealed class ConfigurationParserContext
312+
{
313+
public readonly IConfigurationRoot CurrentConfiguration;
314+
315+
public readonly IConfigurationSection CurrentSection;
316+
317+
public readonly string SectionName;
318+
319+
public readonly IDictionary<string, string> ConnectionStrings;
320+
321+
public ConfigurationParserContext(IConfigurationRoot currentConfiguration, string sectionName)
322+
{
323+
CurrentConfiguration = currentConfiguration;
324+
CurrentSection = currentConfiguration.GetSection(sectionName);
325+
ConnectionStrings = currentConfiguration.Get<Dictionary<string, string>>();
326+
}
327+
328+
public ConfigurationParserContext(IConfigurationSection currentSection, IDictionary<string, string> connectionStrings)
329+
{
330+
CurrentSection = currentSection;
331+
ConnectionStrings = connectionStrings;
332+
}
333+
}
334+
}

0 commit comments

Comments
 (0)