2010-04-06 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System.Design / System.ComponentModel.Design.Serialization / CodeDomComponentSerializationService.cs
blob1c2282b6d789c10aa31c7135d49d1e4aec02a22e
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
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.
30 #if NET_2_0
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;
41 namespace System.ComponentModel.Design.Serialization
43 // A ComponentSerializationService that uses a CodeDomSerializationStore
44 // to serialize Components and MemberDescriptors to CodeStatement and CodeStatementCollection
46 public sealed class CodeDomComponentSerializationService : ComponentSerializationService
48 [Serializable]
49 private class CodeDomSerializationStore : SerializationStore, ISerializable
51 [Serializable]
52 private class Entry
54 private bool _isSerialized;
55 private object _serialized;
56 private bool _absolute;
57 private string _name;
59 protected Entry ()
63 public Entry (string name)
65 if (name == null)
66 throw new ArgumentNullException ("name");
67 _name = name;
68 _isSerialized = false;
69 _absolute = false;
72 public bool IsSerialized {
73 get { return _isSerialized; }
74 set { _isSerialized = value; }
77 public object Serialized {
78 get { return _serialized; }
79 set {
80 _serialized = value;
81 _isSerialized = true;
85 public bool Absolute {
86 get { return _absolute; }
87 set { _absolute = value; }
90 public string Name {
91 get { return _name; }
92 set { _name = value; }
96 [Serializable]
97 private class MemberEntry : Entry
99 private MemberDescriptor _descriptor;
101 protected MemberEntry ()
105 public MemberEntry (MemberDescriptor descriptor)
107 if (descriptor == null)
108 throw new ArgumentNullException ("descriptor");
109 _descriptor = descriptor;
110 base.Name = descriptor.Name;
113 public MemberDescriptor Descriptor {
114 get { return _descriptor; }
115 set { _descriptor = value; }
119 [Serializable]
120 private class ObjectEntry : Entry
122 private Type _type;
123 [NonSerialized]
124 private object _instance;
125 private Dictionary<string,MemberEntry> _members;
126 private bool _entireObject;
128 protected ObjectEntry ()
132 public ObjectEntry (object instance, string name) : base (name)
134 if (instance == null)
135 throw new ArgumentNullException ("instance");
136 _instance = instance;
137 _type = instance.GetType ();
138 _entireObject = false;
141 public Type Type {
142 get { return _type; }
145 public object Instance {
146 get { return _instance; }
147 set {
148 _instance = value;
149 if (value != null)
150 _type = value.GetType ();
154 public Dictionary<string,MemberEntry> Members {
155 get {
156 if (_members == null)
157 _members = new Dictionary <string, MemberEntry> ();
158 return _members;
160 set { _members = value; }
163 public bool IsEntireObject {
164 get { return _entireObject; }
165 set { _entireObject = value; }
169 // When e.g Copy->Pasting a component will not be preserved, but the serialized
170 // data will contain references to the original component name. We handle this
171 // here by checking whether CreateInstance returns a component with a different
172 // name and we map the old name to the new one so that GetInstance will return
173 // a reference to the new component.
175 private class InstanceRedirectorDesignerSerializationManager : IDesignerSerializationManager, IServiceProvider
177 DesignerSerializationManager _manager;
178 private Dictionary <string, string> _nameMap;
180 public InstanceRedirectorDesignerSerializationManager (IServiceProvider provider, IContainer container,
181 bool validateRecycledTypes)
183 if (provider == null)
184 throw new ArgumentNullException ("provider");
185 DesignerSerializationManager manager = new DesignerSerializationManager (provider);
186 manager.PreserveNames = false;
187 if (container != null)
188 manager.Container = container;
189 manager.ValidateRecycledTypes = validateRecycledTypes;
190 _manager = manager;
193 public IDisposable CreateSession ()
195 return _manager.CreateSession ();
198 public IList Errors {
199 get { return _manager.Errors; }
202 object IServiceProvider.GetService (Type service)
204 return ((IServiceProvider)_manager).GetService (service);
207 #region IDesignerSerializationManager Wrapper Implementation
209 void IDesignerSerializationManager.AddSerializationProvider (IDesignerSerializationProvider provider)
211 ((IDesignerSerializationManager)_manager).AddSerializationProvider (provider);
214 void IDesignerSerializationManager.RemoveSerializationProvider (IDesignerSerializationProvider provider)
216 ((IDesignerSerializationManager)_manager).RemoveSerializationProvider (provider);
219 object IDesignerSerializationManager.CreateInstance (Type type, ICollection arguments, string name, bool addToContainer)
221 object instance = ((IDesignerSerializationManager)_manager).CreateInstance (type, arguments, name, addToContainer);
222 string newName = ((IDesignerSerializationManager)_manager).GetName (instance);
223 if (newName != name) {
224 if (_nameMap == null)
225 _nameMap = new Dictionary<string, string> ();
226 _nameMap[name] = newName;
228 return instance;
231 object IDesignerSerializationManager.GetInstance (string name)
233 if (_nameMap != null && _nameMap.ContainsKey (name))
234 return ((IDesignerSerializationManager)_manager).GetInstance (_nameMap[name]);
235 return ((IDesignerSerializationManager)_manager).GetInstance (name);
238 Type IDesignerSerializationManager.GetType (string name)
240 return ((IDesignerSerializationManager)_manager).GetType (name);
243 object IDesignerSerializationManager.GetSerializer (Type type, Type serializerType)
245 return ((IDesignerSerializationManager)_manager).GetSerializer (type, serializerType);
248 string IDesignerSerializationManager.GetName (object instance)
250 return ((IDesignerSerializationManager)_manager).GetName (instance);
253 void IDesignerSerializationManager.SetName (object instance, string name)
255 ((IDesignerSerializationManager)_manager).SetName (instance, name);
258 void IDesignerSerializationManager.ReportError (object error)
260 ((IDesignerSerializationManager)_manager).ReportError (error);
263 ContextStack IDesignerSerializationManager.Context {
264 get { return ((IDesignerSerializationManager)_manager).Context; }
267 PropertyDescriptorCollection IDesignerSerializationManager.Properties {
268 get { return ((IDesignerSerializationManager)_manager).Properties; }
271 event EventHandler IDesignerSerializationManager.SerializationComplete {
272 add { ((IDesignerSerializationManager)_manager).SerializationComplete += value; }
273 remove { ((IDesignerSerializationManager)_manager).SerializationComplete -= value; }
276 event ResolveNameEventHandler IDesignerSerializationManager.ResolveName {
277 add { ((IDesignerSerializationManager)_manager).ResolveName += value; }
278 remove { ((IDesignerSerializationManager)_manager).ResolveName -= value; }
280 #endregion
281 } // InstanceRedirectorDesignerSerializationManager
283 private bool _closed;
284 private Dictionary <string, ObjectEntry> _objects;
285 private IServiceProvider _provider;
286 private ICollection _errors;
288 internal CodeDomSerializationStore () : this (null)
292 internal CodeDomSerializationStore (IServiceProvider provider)
294 _provider = provider;
297 private CodeDomSerializationStore (SerializationInfo info, StreamingContext context)
299 _objects = (Dictionary<string, ObjectEntry>) info.GetValue ("objects", typeof (Dictionary<string, ObjectEntry>));
300 _closed = (bool) info.GetValue ("closed", typeof (bool));
303 void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
305 info.AddValue ("objects", _objects);
306 info.AddValue ("closed", _closed);
309 public override void Close ()
311 if (!_closed) {
312 Serialize (_provider);
313 _closed = true;
317 internal static CodeDomSerializationStore Load (Stream stream)
319 return new BinaryFormatter ().Deserialize (stream) as CodeDomSerializationStore;
322 public override void Save (Stream stream)
324 Close ();
325 new BinaryFormatter ().Serialize (stream, this);
328 private void Serialize (IServiceProvider provider)
330 if (provider == null || _objects == null)
331 return;
333 // Use a new serialization manager to prevent from "deadlocking" the surface one
334 // by trying to create new session when one currently exists
336 InstanceRedirectorDesignerSerializationManager manager =
337 new InstanceRedirectorDesignerSerializationManager (provider, null, false);
338 ((IDesignerSerializationManager)manager).AddSerializationProvider (CodeDomSerializationProvider.Instance);
339 IDisposable session = manager.CreateSession ();
340 foreach (ObjectEntry objectEntry in _objects.Values) {
341 if (objectEntry.IsEntireObject) {
342 CodeDomSerializer serializer = (CodeDomSerializer) ((IDesignerSerializationManager)manager).GetSerializer (objectEntry.Type,
343 typeof (CodeDomSerializer));
344 if (serializer != null) {
345 object serialized = null;
346 if (objectEntry.Absolute)
347 serialized = serializer.SerializeAbsolute (manager,
348 objectEntry.Instance);
349 else
350 serialized = serializer.Serialize (manager, objectEntry.Instance);
351 objectEntry.Serialized = serialized;
353 } else {
354 foreach (MemberEntry memberEntry in objectEntry.Members.Values) {
355 CodeDomSerializer serializer = (CodeDomSerializer) ((IDesignerSerializationManager)manager).GetSerializer (
356 objectEntry.Type, typeof (CodeDomSerializer));
357 if (serializer != null) {
358 object serialized = null;
359 if (memberEntry.Absolute) {
360 serialized = serializer.SerializeMemberAbsolute (manager,
361 objectEntry.Instance,
362 memberEntry.Descriptor);
363 } else {
364 serialized = serializer.SerializeMember (manager,
365 objectEntry.Instance,
366 memberEntry.Descriptor);
368 memberEntry.Serialized = serialized;
373 _errors = manager.Errors;
374 session.Dispose ();
377 internal void AddObject (object instance, bool absolute)
379 if (_closed)
380 throw new InvalidOperationException ("store is closed");
382 if (_objects == null)
383 _objects = new Dictionary <string, ObjectEntry> ();
384 string objectName = GetName (instance);
386 if (!_objects.ContainsKey (objectName)) {
387 ObjectEntry objectEntry = new ObjectEntry (instance, objectName);
388 objectEntry.Absolute = absolute;
389 objectEntry.IsEntireObject = true;
390 _objects[objectName] = objectEntry;
394 internal void AddMember (object owner, MemberDescriptor member, bool absolute)
396 if (_closed)
397 throw new InvalidOperationException ("store is closed");
398 if (member == null)
399 throw new ArgumentNullException ("member");
400 if (owner == null)
401 throw new ArgumentNullException ("owner");
403 if (_objects == null)
404 _objects = new Dictionary <string, ObjectEntry> ();
406 string objectName = GetName (owner);
407 if (!_objects.ContainsKey (objectName))
408 _objects.Add (objectName, new ObjectEntry (owner, objectName));
409 MemberEntry memberEntry = new MemberEntry (member);
410 memberEntry.Absolute = absolute;
411 _objects[objectName].Members[member.Name] = memberEntry;
414 private string GetName (object value)
416 if (value == null)
417 throw new ArgumentNullException ("value");
418 string name = null;
420 IComponent component = value as IComponent;
421 if (component != null && component.Site != null) {
422 if (component.Site is INestedSite)
423 name = ((INestedSite)component.Site).FullName;
424 else
425 name = component.Site != null ? component.Site.Name : null;
426 } else if (value is MemberDescriptor) {
427 name = ((MemberDescriptor) value).Name;
428 } else {
429 name = value.GetHashCode ().ToString ();
432 return name;
435 internal ICollection Deserialize (IServiceProvider provider, IContainer container,
436 bool validateRecycledTypes, bool applyDefaults)
438 List<object> objectInstances = new List<object> ();
440 if (provider == null || _objects == null)
441 return objectInstances;
442 _provider = provider;
444 // Use a new serialization manager to prevent from "deadlocking" the surface one
445 // by trying to create new session when one currently exists
447 InstanceRedirectorDesignerSerializationManager manager =
448 new InstanceRedirectorDesignerSerializationManager (provider, container, validateRecycledTypes);
449 ((IDesignerSerializationManager)manager).AddSerializationProvider (CodeDomSerializationProvider.Instance);
450 IDisposable session = manager.CreateSession ();
451 foreach (ObjectEntry entry in _objects.Values)
452 objectInstances.Add (DeserializeEntry (manager, entry));
453 _errors = manager.Errors;
454 session.Dispose ();
455 return objectInstances;
458 private object DeserializeEntry (IDesignerSerializationManager manager, ObjectEntry objectEntry)
460 object deserialized = null;
462 if (objectEntry.IsEntireObject) {
463 CodeDomSerializer serializer = (CodeDomSerializer) manager.GetSerializer (objectEntry.Type,
464 typeof (CodeDomSerializer));
465 if (serializer != null) {
466 deserialized = serializer.Deserialize (manager, objectEntry.Serialized);
467 // check if the name of the object has changed
468 // (if it e.g clashes with another name)
469 string newName = manager.GetName (deserialized);
470 if (newName != objectEntry.Name)
471 objectEntry.Name = newName;
473 } else {
474 foreach (MemberEntry memberEntry in objectEntry.Members.Values) {
475 CodeDomSerializer serializer = (CodeDomSerializer) manager.GetSerializer (objectEntry.Type,
476 typeof (CodeDomSerializer));
477 if (serializer != null)
478 serializer.Deserialize (manager, memberEntry.Serialized);
482 return deserialized;
485 public override ICollection Errors {
486 get {
487 if (_errors == null)
488 _errors = new object[0];
489 return _errors;
492 } // CodeDomSerializationStore
494 private IServiceProvider _provider;
496 public CodeDomComponentSerializationService () : this (null)
500 public CodeDomComponentSerializationService (IServiceProvider provider)
502 _provider = provider;
505 public override SerializationStore CreateStore ()
507 return new CodeDomSerializationStore (_provider);
510 public override SerializationStore LoadStore (Stream stream)
512 return CodeDomSerializationStore.Load (stream);
515 public override ICollection Deserialize (SerializationStore store)
517 return this.Deserialize (store, null);
520 public override ICollection Deserialize (SerializationStore store, IContainer container)
522 return DeserializeCore (store, container, true, true);
525 public override void DeserializeTo (SerializationStore store, IContainer container, bool validateRecycledTypes, bool applyDefaults)
527 DeserializeCore (store, container, validateRecycledTypes, applyDefaults);
530 private ICollection DeserializeCore (SerializationStore store, IContainer container, bool validateRecycledTypes,
531 bool applyDefaults)
533 CodeDomSerializationStore codeDomStore = store as CodeDomSerializationStore;
534 if (codeDomStore == null)
535 throw new InvalidOperationException ("store type unsupported");
536 return codeDomStore.Deserialize (_provider, container, validateRecycledTypes, applyDefaults);
539 public override void Serialize (SerializationStore store, object value)
541 SerializeCore (store, value, false);
544 public override void SerializeAbsolute (SerializationStore store, object value)
546 SerializeCore (store, value, true);
549 public override void SerializeMember (SerializationStore store, object owningObject, MemberDescriptor member)
551 SerializeMemberCore (store, owningObject, member, false);
554 public override void SerializeMemberAbsolute (SerializationStore store, object owningObject, MemberDescriptor member)
556 SerializeMemberCore (store, owningObject, member, true);
559 private void SerializeCore (SerializationStore store, object value, bool absolute)
561 if (value == null)
562 throw new ArgumentNullException ("value");
563 if (store == null)
564 throw new ArgumentNullException ("store");
566 CodeDomSerializationStore codeDomStore = store as CodeDomSerializationStore;
567 if (store == null)
568 throw new InvalidOperationException ("store type unsupported");
570 codeDomStore.AddObject (value, absolute);
573 private void SerializeMemberCore (SerializationStore store, object owningObject, MemberDescriptor member, bool absolute)
575 if (member == null)
576 throw new ArgumentNullException ("member");
577 if (owningObject == null)
578 throw new ArgumentNullException ("owningObject");
579 if (store == null)
580 throw new ArgumentNullException ("store");
582 CodeDomSerializationStore codeDomStore = store as CodeDomSerializationStore;
583 if (codeDomStore == null)
584 throw new InvalidOperationException ("store type unsupported");
585 codeDomStore.AddMember (owningObject, member, absolute);
589 #endif