1 #Region "Microsoft.VisualBasic::bd0cb0e1dad0a20c80c0102e380f752f, Microsoft.VisualBasic.Core\ComponentModel\Settings\Inf\Serialization.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     '     Class Serialization
35     
36     '         Properties: Sections
37     
38     '         Function: __getDefaultPath, Load, Save
39     
40     '     Class IniMapIO
41     
42     '         Properties: Path
43     
44     '         Constructor: (+1 OverloadsSub New
45     '         FunctionToString
46     
47     '     Module IOProvider
48     
49     '         Function: __getPath, __getSections, EmptySection, (+2 Overloads) LoadProfile, (+2 Overloads) WriteProfile
50     
51     
52     ' /********************************************************************************/
53
54 #End Region
55
56 Imports System.Reflection
57 Imports System.Runtime.CompilerServices
58 Imports System.Text
59 Imports System.Xml.Serialization
60 Imports Microsoft.VisualBasic.ComponentModel.DataSourceModel.SchemaMaps
61 Imports Microsoft.VisualBasic.Language
62 Imports Microsoft.VisualBasic.Language.UnixBash.FileSystem
63 Imports Microsoft.VisualBasic.Serialization.JSON
64
65 Namespace ComponentModel.Settings.Inf
66
67     Public Class Serialization : Inherits ITextFile
68
69         <XmlElement> Public Property Sections As Section()
70
71         Public Shared Function Load(path As StringAs Serialization
72             Throw New NotImplementedException
73         End Function
74
75         Public Overrides Function Save(Optional FilePath As String = ""Optional Encoding As Encoding = NothingAs Boolean
76             Throw New NotImplementedException
77         End Function
78
79         Protected Overrides Function __getDefaultPath() As String
80             Return FilePath
81         End Function
82     End Class
83
84     ''' <summary>
85     ''' The path parameter can be shortcut by method <see cref="PathMapper.GetMapPath"/>.
86     ''' additional, using ``@fileName`` for using <see cref="App.GetFile(String)"/> API.
87     ''' </summary>
88     <AttributeUsage(AttributeTargets.Class, AllowMultiple:=False, Inherited:=True)>
89     Public Class IniMapIO : Inherits Attribute
90
91         Public ReadOnly Property Path As String
92
93         ''' <summary>
94         ''' The path parameter can be shortcut by method <see cref="PathMapper.GetMapPath"/>
95         ''' </summary>
96         ''' <param name="path"></param>
97         Sub New(path As String)
98             If path.First = "@"Then
99                 Me.Path = App.GetFile(Mid(path, 2))
100             Else
101                 Me.Path = PathMapper.GetMapPath(path)
102             End If
103         End Sub
104
105         Public Overrides Function ToString() As String
106             Return Me.GetJson
107         End Function
108     End Class
109
110     ''' <summary>
111     ''' 在这个模块之中提供了.NET对象与``*.ini``配置文件之间的相互映射的序列化操作
112     ''' </summary>
113     Public Module IOProvider
114
115         <MethodImpl(MethodImplOptions.AggressiveInlining)>
116         <Extension>
117         Private Function EmptySection(x As Type, section As PropertyInfo) As String
118             Return $"Property [{x.Name}\({section.PropertyType.Name}){section.Name}] for ini section is null."
119         End Function
120
121         ''' <summary>
122         ''' 将目标对象写为``*.ini``文件
123         ''' </summary>
124         ''' <typeparam name="T"></typeparam>
125         ''' <param name="x"></param>
126         ''' <param name="path"></param>
127         ''' <returns></returns>
128         <Extension>
129         Public Function WriteProfile(Of T As Class)(x As T, path$) As Boolean
130             Dim ini As New IniFile(path)
131             Dim msg$
132
133             For Each section As PropertyInfo In __getSections(Of T)()
134                 Dim obj As Object = section.GetValue(x, Nothing)
135                 Dim schema As Type = section.PropertyType
136
137                 If obj Is Nothing Then
138                     msg = GetType(T).EmptySection(section)
139                     obj = Activator.CreateInstance(schema)
140
141                     Call msg.Warning
142                     Call App.LogException(msg)
143                 End If
144
145                 Call ClassMapper.ClassDumper(
146                     x:=obj,
147                     type:=schema,
148                     ini:=ini
149                 )
150             Next
151
152             Call $"Ini profile data was saved at location: {path.GetFullPath}".__INFO_ECHO
153
154             Return True
155         End Function
156
157         ''' <summary>
158         ''' 属性的类型需要定义<see cref="ClassName"/>,Section类型里面的属性还需要
159         ''' 定义<see cref="DataFrameColumnAttribute"/>,否则将不会将对应的属性的值
160         ''' 写入到ini文件之中。
161         ''' </summary>
162         ''' <typeparam name="T"></typeparam>
163         ''' <param name="x"></param>
164         ''' <returns></returns>
165         ''' 
166         <MethodImpl(MethodImplOptions.AggressiveInlining)>
167         <Extension>
168         Public Function WriteProfile(Of T As Class)(x As T) As Boolean
169             Return x.WriteProfile(__getPath(Of T))
170         End Function
171
172         Private Function __getSections(Of T As Class)() As PropertyInfo()
173             Dim properties As PropertyInfo() =
174                 GetType(T).GetProperties(bindingAttr:=
175                 BindingFlags.Instance Or
176                 BindingFlags.Public
177             )
178
179             properties = LinqAPI.Exec(Of PropertyInfo) _
180  _
181                 () <= From p As PropertyInfo
182                       In properties
183                       Let type As Type = p.PropertyType
184                       Let attr As ClassName = type.GetAttribute(Of ClassName)
185                       Where Not attr Is Nothing
186                       Select p
187
188             Return properties
189         End Function
190
191         ''' <summary>
192         ''' 从指定的``*.ini``文件之中加载配置数据
193         ''' </summary>
194         ''' <typeparam name="T"></typeparam>
195         ''' <param name="path"></param>
196         ''' <returns></returns>
197         <Extension>
198         Public Function LoadProfile(Of T As Class)(path As StringAs T
199             Dim obj As Object = Activator.CreateInstance(Of T)
200             Dim ini As New IniFile(path)
201
202             For Each prop As PropertyInfo In __getSections(Of T)()
203                 Dim x As Object = ClassMapper.ClassWriter(ini, prop.PropertyType)
204                 Call prop.SetValue(obj, x, Nothing)
205             Next
206
207             Return DirectCast(obj, T)
208         End Function
209
210         Private Function __getPath(Of T As Class)() As String
211             Dim path As IniMapIO = GetType(T).GetAttribute(Of IniMapIO)
212
213             If path Is Nothing Then
214                 Throw New Exception("Could not found path mapping! @" & GetType(T).FullName)
215             Else
216                 Return path.Path
217             End If
218         End Function
219
220         Public Function LoadProfile(Of T As Class)(Optional ByRef fileExists As Boolean = FalseOptional ByRef path$ = NothingAs T
221             path = __getPath(Of T)()
222             fileExists = path.FileExists
223
224             If Not fileExists Then  ' 文件不存在,则直接写文件了
225                 Dim obj As T = Activator.CreateInstance(Of T)
226                 Call obj.WriteProfile
227                 Return obj
228             Else
229                 Return path.LoadProfile(Of T)
230             End If
231         End Function
232     End Module
233 End Namespace