1 #Region "Microsoft.VisualBasic::5ecd2229c267c6f208a59d6c70edc280, Microsoft.VisualBasic.Core\Serialization\ConfigMappings\ConfigurationMappings.vb"
2
3     ' Author:
4     
5     '       asuka (amethyst.asuka@gcmodeller.org)
6     '       xie (genetics@smrucc.org)
7     '       xieguigang (xie.guigang@live.com)
8     
9     ' Copyright (c) 2018 GPL3 Licensed
10     
11     
12     ' GNU GENERAL PUBLIC LICENSE (GPL3)
13     
14     
15     ' This program is free software: you can redistribute it and/or modify
16     ' it under the terms of the GNU General Public License as published by
17     ' the Free Software Foundation, either version 3 of the License, or
18     ' (at your option) any later version.
19     
20     ' This program is distributed in the hope that it will be useful,
21     ' but WITHOUT ANY WARRANTY; without even the implied warranty of
22     ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     ' GNU General Public License for more details.
24     
25     ' You should have received a copy of the GNU General Public License
26     ' along with this program. If not, see <http://www.gnu.org/licenses/>.
27
28
29
30     ' /********************************************************************************/
31
32     ' Summaries:
33
34     '     Module ConfigurationMappings
35     
36     '         Function: __getCustomMapping, __getReads_MappingHandle, __getWrite_MappingHandle, __knowsIsIgnored, GetNodeMapping
37     '                   LoadMapping, (+2 Overloads) WriteMapping
38     
39     
40     ' /********************************************************************************/
41
42 #End Region
43
44 Imports System.Reflection
45 Imports Microsoft.VisualBasic.ComponentModel.DataSourceModel
46 Imports Microsoft.VisualBasic.Language
47 Imports Microsoft.VisualBasic.Scripting.Runtime
48
49 Namespace Serialization
50
51 #If NET_40 = 0 Then
52
53     ''' <summary>
54     ''' 最基本的思想是将属性值按照同名属性名称在A和B两个对象类型之间进行映射,即A与B两个对象之间必须要具备相同的属性名称,才可以产生映射,请注意在本对象之中仅能够映射最基本的值类型的数据类型
55     ''' 对于一些自定义的映射操作,请在目标数据模型之中定义自定义的映射函数,要求为函数只有一个参数,参数类型和返回值类型分别为映射的两个节点的数据类型,程序会使用反射自动查找
56     ''' </summary>
57     ''' <remarks></remarks>
58     Public Module ConfigurationMappings
59
60         ''' <summary>
61         ''' 从源江基本的值类型映射到数据模型,以将配置数据读取出来并进行加载
62         ''' </summary>
63         ''' <typeparam name="T">数据模型</typeparam>
64         ''' <typeparam name="TMaps">源</typeparam>
65         ''' <returns></returns>
66         ''' <remarks></remarks>
67         Public Function LoadMapping(Of T As Class, TMaps As Class)(source As TMaps) As T
68             Dim Mappings = GetNodeMapping(Of T, TMaps)(source)
69             Dim DataModel As T = Activator.CreateInstance(Of T)()
70
71             For Each Node In Mappings '读取数据
72                 Dim value As Object = Node.Source.GetValue(source)
73                 Dim str As String = CStrSafe(value, "")
74                 value = Node.SourceToMappingCasting(str)
75                 Call Node.Mapping.SetValue(DataModel, value)
76             Next
77
78             Return DataModel
79         End Function
80
81         Public Function WriteMapping(Of T As Class, TMaps As Class)(model As T, ByRef WriteToSource As TMaps) As TMaps
82             Dim Mappings = GetNodeMapping(Of T, TMaps)(Nothing)
83
84             For Each Node In Mappings '写数据
85                 If Node.MappingToSourceCasting Is Nothing Then
86                     Continue For
87                 End If
88
89                 Dim value As Object = Node.Mapping.GetValue(model)
90                 Dim str As String = Node.MappingToSourceCasting(value)
91                 Call Node.Source.SetValue(WriteToSource, str)
92             Next
93
94             Return WriteToSource
95         End Function
96
97         ''' <summary>
98         ''' 从数据模型将值类型数据映射回源,以将配置数据写入文件
99         ''' </summary>
100         ''' <typeparam name="T">数据模型</typeparam>
101         ''' <typeparam name="TMaps">源</typeparam>
102         ''' <param name="Model"></param>
103         ''' <returns></returns>
104         ''' <remarks></remarks>
105         Public Function WriteMapping(Of T As Class, TMaps As Class)(Model As T) As TMaps
106             Dim Source As TMaps = Activator.CreateInstance(Of TMaps)()
107             Return WriteMapping(Of T, TMaps)(Model, WriteToSource:=Source)
108         End Function
109
110         Private Function __knowsIsIgnored(p As PropertyInfo) As Boolean
111             Dim c_attrs As Object() = p.GetCustomAttributes(attributeType:=GetType(MappingsIgnored), inherit:=False)
112             Return Not c_attrs.IsNullOrEmpty
113         End Function
114
115         ''' <summary>
116         ''' 获取从源映射至数据模型的映射过程
117         ''' </summary>
118         ''' <typeparam name="T">数据模型</typeparam>
119         ''' <typeparam name="TMaps">源</typeparam>
120         ''' <returns></returns>
121         ''' <remarks></remarks>
122         Public Function GetNodeMapping(Of T As Class, TMaps As Class)(obj_source As ObjectAs NodeMapping()
123             Dim LQuery As PropertyInfo() = LinqAPI.Exec(Of PropertyInfo) <=
124                 From p As PropertyInfo
125                 In GetType(TMaps).GetProperties(BindingFlags.Instance Or BindingFlags.Public)
126                 Where Not __knowsIsIgnored(p) AndAlso
127                     DataFramework.StringParsers.ContainsKey(p.PropertyType)
128                 Select p '获取所有的数据源之中的映射
129             Dim T_EntityType As Type = GetType(T)
130             Dim CustomMappings As MethodInfo() = LinqAPI.Exec(Of MethodInfo) <=
131                 From entry As MethodInfo
132                 In GetType(TMaps).GetMethods()
133                 Where entry.ReturnType <> GetType(System.Void) AndAlso
134                     entry.GetParameters.Length = 1
135                 Select entry
136
137             Dim Mappings = From p As PropertyInfo
138                            In T_EntityType.GetProperties(BindingFlags.Instance Or BindingFlags.Public)
139                            Let array As PropertyInfo =
140                                LQuery.Where(Function(prop) String.Equals(prop.Name, p.Name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault
141                            Where Not array Is Nothing AndAlso
142                                Not __knowsIsIgnored(p)
143                            Select source = array,
144                                MappingToModel = p         ' 获取数据模型之中的同名的映射属性
145             Dim out = From mapping
146                       In Mappings
147                       Let sourceMapping = __getReads_MappingHandle(mapping.source, mapping.MappingToModel, CustomMappings, obj_source)
148                       Let model2Mapping = __getWrite_MappingHandle(mapping.source, mapping.MappingToModel, CustomMappings)
149                       Select mapping.source,
150                           mapping.MappingToModel,
151                           sourceMapping,
152                           model2Mapping    ' 获取具体的映射过程
153
154             Return LinqAPI.Exec(Of NodeMapping) <=
155  _
156                 From map
157                 In out
158                 Where Not (map.sourceMapping Is Nothing)
159                 Let nodeMap As NodeMapping = New NodeMapping With {
160                     .Source = map.source,
161                     .Mapping = map.MappingToModel,
162                     .SourceToMappingCasting = map.sourceMapping,
163                     .MappingToSourceCasting = map.model2Mapping
164                 }
165                 Select nodeMap     ' 返回映射句柄,为了简化程序设计,数据模型至源文件的映射可以不必定义。但是当需要使用本模块进行配置文件的写操作的时候,映射至源文件的方法则非常有必要要进行定义了
166         End Function
167
168         Private Function __getWrite_MappingHandle(source As PropertyInfo, Model As PropertyInfo, Methods As MethodInfo()) As IStringBuilder
169             If DataFramework.StringBuilders.ContainsKey(Model.PropertyType) Then
170                 Return DataFramework.StringBuilders(Model.PropertyType)
171             Else
172                 Dim Method As MethodInfo = __getCustomMapping(
173                     p_Type:=Model.PropertyType,
174                     ReturnedType:=source.PropertyType,
175                     Methods:=Methods)
176                 Return Function(obj As ObjectDirectCast(Method.Invoke(Nothing, {obj}), String)
177             End If
178         End Function
179
180         Private Function __getReads_MappingHandle(source As PropertyInfo, Model As PropertyInfo, Methods As MethodInfo(), obj_source As ObjectAs IStringParser
181             If DataFramework.StringParsers.ContainsKey(Model.PropertyType) Then
182                 Return DataFramework.StringParsers(Model.PropertyType)
183             Else
184                 Dim method As MethodInfo = __getCustomMapping(
185                     p_Type:=source.PropertyType,
186                     ReturnedType:=Model.PropertyType,
187                     Methods:=Methods)
188 #If DEBUG Then
189                 If method Is Nothing Then
190                     Call $"{source.Name} --> {Model.Name} is incomplete!".Warning
191                 End If
192 #End If
193                 Return Function(s$)
194                            Return method.Invoke(obj_source, {s})
195                        End Function
196             End If
197         End Function
198
199         Private Function __getCustomMapping(p_Type As Type, ReturnedType As Type, Methods As MethodInfo()) As MethodInfo
200             Dim LQuery As MethodInfo = LinqAPI.DefaultFirst(Of MethodInfo) <=
201                 From entryPoint As MethodInfo
202                 In Methods
203                 Where entryPoint.GetParameters.First.ParameterType = p_Type AndAlso
204                     entryPoint.ReturnType = ReturnedType
205                 Select entryPoint
206
207             Return LQuery
208         End Function
209     End Module
210 #End If
211 End Namespace