2008-01-04 Ivan N. Zlatev <contact@i-nz.net>
[mono.git] / mcs / class / System.Design / System.ComponentModel.Design.Serialization / CodeDomComponentSerializationService.cs
1 //
2 // System.ComponentModel.Design.Serialization.CodeDomComponentSerializationService
3 //
4 // Authors:      
5 //        Ivan N. Zlatev (contact@i-nZ.net)
6 //
7 // (C) 2007 Ivan N. Zlatev
8
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 #if NET_2_0
31
32 using System;
33 using System.Runtime.Serialization;
34 using System.Runtime.Serialization.Formatters.Binary;
35 using System.ComponentModel;
36 using System.ComponentModel.Design.Serialization;
37 using System.Collections;
38 using System.Collections.Generic;
39 using System.IO;
40
41 namespace System.ComponentModel.Design.Serialization
42 {
43         // A ComponentSerializationService that uses a CodeDomSerializationStore 
44         // to serialize Components and MemberDescriptors to CodeStatement and CodeStatementCollection
45         //
46         public sealed class CodeDomComponentSerializationService : ComponentSerializationService
47         {
48                 [Serializable]
49                 private class CodeDomSerializationStore : SerializationStore
50                 {
51
52                         [Serializable]
53                         private class Entry
54                         {
55                                 private bool _isSerialized;
56                                 private object _serialized;
57                                 private object _deserialized;
58                                 private bool _isDeserialized;
59                                 private bool _absolute;
60                                 private string _name;
61
62                                 protected Entry ()
63                                 {
64                                 }
65
66                                 public Entry (string name)
67                                 {
68                                         if (name == null)
69                                                 throw new ArgumentNullException ("name");
70                                         _name = name;
71                                         _isDeserialized = true;
72                                         _isSerialized = false;
73                                         _absolute = false;
74                                 }
75
76                                 public bool IsSerialized {
77                                         get { return _isSerialized; }
78                                         set { _isSerialized = value; }
79                                 }
80
81                                 public object Serialized {
82                                         get { return _serialized; }
83                                         set { 
84                                                 _serialized = value;
85                                                 _isSerialized = true;
86                                         }
87                                 }
88
89                                 public bool IsDeserialized {
90                                         get { return _isDeserialized; }
91                                         set { _isDeserialized = value; }
92                                 }
93
94                                 public object Deserialized {
95                                         get { return _deserialized; }
96                                         set { 
97                                                 _deserialized = value;
98                                                 _isDeserialized = true;
99                                         }
100                                 }
101
102                                 public bool Absolute {
103                                         get { return _absolute; }
104                                         set { _absolute = value; }
105                                 }
106
107                                 public string Name {
108                                         get { return _name; }
109                                         set { _name = value; }
110                                 }
111                         }
112
113                         [Serializable]
114                         private class MemberEntry : Entry
115                         {
116                                 private MemberDescriptor _descriptor;
117
118                                 protected MemberEntry ()
119                                 {
120                                 }
121
122                                 public MemberEntry (MemberDescriptor descriptor)
123                                 {
124                                         if (descriptor == null)
125                                                 throw new ArgumentNullException ("descriptor");
126                                         _descriptor = descriptor;
127                                         base.Name = descriptor.Name;
128                                 }
129
130                                 public MemberDescriptor Descriptor {
131                                         get { return _descriptor; }
132                                         set { _descriptor = value; }
133                                 }
134                         }
135
136                         [Serializable]
137                         private class ObjectEntry : Entry
138                         {
139                                 private Type _type;
140                                 [NonSerialized]
141                                 private object _instance;
142                                 private Dictionary<string,MemberEntry> _members;
143                                 private bool _entireObject;
144
145                                 protected ObjectEntry ()
146                                 {
147                                 }
148
149                                 public ObjectEntry (object instance, string name) : base (name)
150                                 {
151                                         if (instance == null)
152                                                 throw new ArgumentNullException ("instance");
153                                         _instance = instance;
154                                         _type = instance.GetType ();
155                                         _entireObject = false;
156                                 }
157
158                                 public Type Type {
159                                         get { return _type; }
160                                 }
161
162                                 public object Instance {
163                                         get { return _instance; }
164                                         set { 
165                                                 _instance = value;
166                                                 if (value != null)
167                                                         _type = value.GetType ();
168                                         }
169                                 }
170
171                                 public Dictionary<string,MemberEntry> Members {
172                                         get { 
173                                                 if (_members == null)
174                                                         _members = new Dictionary <string, MemberEntry> ();
175                                                 return _members; 
176                                         }
177                                         set { _members = value; }
178                                 }
179
180                                 public bool EntireObject {
181                                         get { return _entireObject; }
182                                         set { _entireObject = value; }
183                                 }
184                         }
185
186                         private bool _closed;
187                         private Dictionary <string, ObjectEntry> _objects;
188                         private IServiceProvider _provider;
189                         private ICollection _errors;
190
191                         internal CodeDomSerializationStore () : this (null)
192                         {
193                         }
194
195                         internal CodeDomSerializationStore (IServiceProvider provider)
196                         {
197                                 _provider = provider;
198                         }
199
200                         public override void Close () 
201                         {
202                                 if (!_closed) {
203                                         Serialize (_provider);
204                                         _closed = true;
205                                 }
206                         }
207
208                         internal static CodeDomSerializationStore Load (Stream stream)
209                         {
210                                 return new BinaryFormatter ().Deserialize (stream) as CodeDomSerializationStore;
211                         }
212
213                         public override void Save (Stream stream) 
214                         {
215                                 Close ();
216                                 new BinaryFormatter ().Serialize (stream, this);
217                         }
218
219                         private void Serialize (IServiceProvider provider)
220                         {
221                                 if (provider == null)
222                                         return;
223                                 DesignerSerializationManager manager = provider.GetService (typeof (IDesignerSerializationManager)) as DesignerSerializationManager;
224                                 if (manager == null)
225                                         return;
226
227                                 using (IDisposable session = manager.CreateSession ()) {
228                                         foreach (ObjectEntry objectEntry in _objects.Values) {
229                                                 if (objectEntry.EntireObject) {
230                                                         CodeDomSerializer serializer = (CodeDomSerializer) manager.GetSerializer (objectEntry.Type, 
231                                                                                                                 typeof (CodeDomSerializer));
232                                                         if (serializer != null) {
233                                                                 object serialized = null;
234                                                                 if (objectEntry.Absolute)
235                                                                         serialized = serializer.SerializeAbsolute (manager, objectEntry.Instance);
236                                                                 else
237                                                                         serialized = serializer.Serialize (manager, objectEntry.Instance);
238                                                                 if (serialized != null)
239                                                                         objectEntry.Serialized = serialized;
240                                                         }
241                                                 } else {
242                                                         foreach (MemberEntry memberEntry in objectEntry.Members.Values) {
243                                                                 CodeDomSerializer serializer = (CodeDomSerializer) manager.GetSerializer (
244                                                                         objectEntry.Type, typeof (CodeDomSerializer));
245                                                                 if (serializer != null) {
246                                                                         object serialized = null;
247                                                                         if (memberEntry.Absolute) {
248                                                                                         serialized = serializer.SerializeMemberAbsolute (manager, 
249                                                                                                                                          objectEntry.Instance, 
250                                                                                                                                          memberEntry.Descriptor);
251                                                                         } else {
252                                                                                         serialized = serializer.SerializeMember (manager,
253                                                                                                                                  objectEntry.Instance, 
254                                                                                                                                  memberEntry.Descriptor);
255                                                                         }
256                                                                         if (serialized != null)
257                                                                                 memberEntry.Serialized = serialized;
258                                                                 }
259                                                         }
260                                                 }
261                                         }
262                                         _errors = manager.Errors;
263                                 }
264                         }
265
266                         internal void AddObject (object instance, bool absolute)
267                         {
268                                 if (_closed)
269                                         throw new InvalidOperationException ("store is closed");
270
271                                 if (_objects == null)
272                                         _objects = new Dictionary <string, ObjectEntry> ();
273                                 string objectName = GetName (instance);
274
275                                 if (!_objects.ContainsKey (objectName)) {
276                                         ObjectEntry objectEntry = new ObjectEntry (instance, objectName);
277                                         objectEntry.Absolute = absolute;
278                                         objectEntry.EntireObject = true;
279                                         _objects[objectName] = objectEntry;
280                                 }
281                         }
282
283                         internal void AddMember (object owner, MemberDescriptor member, bool absolute)
284                         {
285                                 if (_closed)
286                                         throw new InvalidOperationException ("store is closed");
287                                 if (member == null)
288                                         throw new ArgumentNullException ("member");
289                                 if (owner == null)
290                                         throw new ArgumentNullException ("owner");
291
292                                 if (_objects == null)
293                                         _objects = new Dictionary <string, ObjectEntry> ();
294                                 string objectName = GetName (owner);
295
296                                 if (!_objects.ContainsKey (objectName)) {
297                                         ObjectEntry objectEntry = new ObjectEntry (owner, objectName);
298                                         MemberEntry memberEntry = new MemberEntry (member);
299                                         memberEntry.Absolute = absolute;
300                                         objectEntry.Members[member.Name] = memberEntry;
301                                         _objects[objectName] = objectEntry;
302                                 }
303                         }
304
305                         private string GetName (object value)
306                         {
307                                 string name = null;
308
309                                 IComponent component = value as IComponent;
310                                 if (component != null) {
311                                         if (component.Site is INestedSite)
312                                                 name = ((INestedSite)component.Site).FullName;
313                                         else
314                                                 name = component.Site != null ? component.Site.Name : null;
315                                 } else if (value is MemberDescriptor) {
316                                         name = ((MemberDescriptor) value).Name;
317                                 } else {
318                                         name = value.GetHashCode ().ToString ();
319                                 }
320
321                                 return name;
322                         }
323
324                         internal ICollection Deserialize (IServiceProvider provider, IContainer container, 
325                                                           bool validateRecycledTypes, bool applyDefaults)
326                         {
327                                 List<object> objectInstances = new List<object> ();
328
329                                 if (provider == null)
330                                         return objectInstances;
331                                 _provider = provider;
332
333                                 DesignerSerializationManager manager = provider.GetService 
334                                         (typeof (IDesignerSerializationManager)) as DesignerSerializationManager;
335                                 if (manager == null)
336                                         return objectInstances;
337
338                                 bool validateRecycleBackup = manager.ValidateRecycledTypes;
339                                 IContainer containerBackup = manager.Container;
340
341                                 if (container != null)
342                                         manager.Container = container;
343
344                                 using (IDisposable session = manager.CreateSession ()) {
345                                         ((IDesignerSerializationManager) manager).ResolveName += OnResolveInstance;
346                                         foreach (ObjectEntry entry in _objects.Values)
347                                                 objectInstances.Add (DeserializeEntry (manager, entry));
348                                         ((IDesignerSerializationManager) manager).ResolveName -= OnResolveInstance;
349                                         _errors = manager.Errors;
350                                 }
351
352                                 manager.ValidateRecycledTypes = validateRecycleBackup;
353                                 manager.Container = containerBackup;
354                                 return objectInstances;
355                         }
356
357                         private void OnResolveInstance (object sender, ResolveNameEventArgs args)
358                         {
359                                 if (args.Value == null && _objects != null && _objects.ContainsKey (args.Name)) {
360                                         IDesignerSerializationManager manager = _provider.GetService 
361                                                 (typeof (IDesignerSerializationManager)) as IDesignerSerializationManager;
362                                         if (manager != null) {
363                                                 ObjectEntry entry = _objects[args.Name];
364                                                 if (entry.EntireObject)
365                                                         args.Value = DeserializeEntry (manager, entry);
366                                         }
367                                 }
368                         }
369
370                         private object DeserializeEntry (IDesignerSerializationManager manager, ObjectEntry objectEntry)
371                         {
372                                 object deserialized = null;
373
374                                 if (objectEntry.EntireObject) {
375                                         if (objectEntry.IsDeserialized) {
376                                                 deserialized = objectEntry.Deserialized;
377                                         } else {
378                                                 CodeDomSerializer serializer = (CodeDomSerializer) manager.GetSerializer (objectEntry.Type, 
379                                                                                                                           typeof (CodeDomSerializer));
380                                                 if (serializer != null) {
381                                                         deserialized = serializer.Deserialize (manager, objectEntry.Serialized);
382                                                         objectEntry.Deserialized = deserialized;
383                                                         // check if the name of the object has changed
384                                                         // (if it e.g clashes with another name)
385                                                         string newName = manager.GetName (deserialized);
386                                                         if (newName != objectEntry.Name)
387                                                                 objectEntry.Name = newName;
388                                                 }
389                                         }
390                                 } else {
391                                         foreach (MemberEntry memberEntry in objectEntry.Members.Values) {
392                                                 if (!memberEntry.IsDeserialized) {
393                                                         CodeDomSerializer serializer = (CodeDomSerializer) manager.GetSerializer (objectEntry.Type, 
394                                                                                                                                   typeof (CodeDomSerializer));
395                                                         if (serializer != null) {
396                                                                 serializer.Deserialize (manager, memberEntry.Serialized);
397                                                                 memberEntry.IsDeserialized = true;
398                                                         }
399                                                 }
400                                         }
401                                 }
402
403                                 return deserialized;
404                         }
405
406                         public override ICollection Errors {
407                                 get {
408                                         if (_errors == null)
409                                                 _errors = new object[0];
410                                         return _errors;
411                                 }
412                         }
413                 } // CodeDomSerializationStore
414
415                 private IServiceProvider _provider;
416
417                 public CodeDomComponentSerializationService () : this (null)
418                 {
419                 }
420
421                 public CodeDomComponentSerializationService (IServiceProvider provider)
422                 {
423                         _provider = provider;
424                 }
425
426                 public override SerializationStore CreateStore ()
427                 {
428                         return new CodeDomSerializationStore (_provider);
429                 }
430
431                 public override SerializationStore LoadStore (Stream stream)
432                 {
433                         return CodeDomSerializationStore.Load (stream);
434                 }
435
436                 public override ICollection Deserialize (SerializationStore store)
437                 {
438                         return this.Deserialize (store, null);
439                 }
440
441                 public override ICollection Deserialize (SerializationStore store, IContainer container)
442                 {
443                         return DeserializeCore (store, container, true, true);
444                 }
445
446                 public override void DeserializeTo (SerializationStore store, IContainer container, bool validateRecycledTypes, bool applyDefaults)
447                 {
448                         DeserializeCore (store, container, validateRecycledTypes, applyDefaults);
449                 }
450
451                 private ICollection DeserializeCore (SerializationStore store, IContainer container, bool validateRecycledTypes, 
452                                                      bool applyDefaults)
453                 {
454                         CodeDomSerializationStore codeDomStore = store as CodeDomSerializationStore;
455                         if (codeDomStore == null)
456                                 throw new InvalidOperationException ("store type unsupported");
457                         return codeDomStore.Deserialize (_provider, container, validateRecycledTypes, applyDefaults);
458                 }
459
460                 public override void Serialize (SerializationStore store, object value)
461                 {
462                         SerializeCore (store, value, false);
463                 }
464
465                 public override void SerializeAbsolute (SerializationStore store, object value)
466                 {
467                         SerializeCore (store, value, true);
468                 }
469
470                 public override void SerializeMember (SerializationStore store, object owningObject, MemberDescriptor member)
471                 {
472                         SerializeMemberCore (store, owningObject, member, false);
473                 }
474
475                 public override void SerializeMemberAbsolute (SerializationStore store, object owningObject, MemberDescriptor member)
476                 {
477                         SerializeMemberCore (store, owningObject, member, true);
478                 }
479
480                 private void SerializeCore (SerializationStore store, object value, bool absolute)
481                 {
482                         if (value == null)
483                                 throw new ArgumentNullException ("value");
484                         if (store == null)
485                                 throw new ArgumentNullException ("store");
486
487                         CodeDomSerializationStore codeDomStore = store as CodeDomSerializationStore;
488                         if (store == null)
489                                 throw new InvalidOperationException ("store type unsupported");
490
491                         codeDomStore.AddObject (value, absolute);
492                 }
493
494                 private void SerializeMemberCore (SerializationStore store, object owningObject, MemberDescriptor member, bool absolute)
495                 {
496                         if (member == null)
497                                 throw new ArgumentNullException ("member");
498                         if (owningObject == null)
499                                 throw new ArgumentNullException ("owningObject");
500                         if (store == null)
501                                 throw new ArgumentNullException ("store");
502
503                         CodeDomSerializationStore codeDomStore = store as CodeDomSerializationStore;
504                         if (codeDomStore == null)
505                                 throw new InvalidOperationException ("store type unsupported");
506                         codeDomStore.AddMember (owningObject, member, absolute);
507                 }
508         }
509 }
510 #endif