Implement MachineKey.Protect and MachineKey.Unprotect
[mono.git] / mcs / class / System.ComponentModel.DataAnnotations / System.ComponentModel.DataAnnotations / AssociatedMetadataTypeTypeDescriptor.cs
1 //
2 // AssociatedMetadataTypeTypeDescriptionProvider.cs
3 //
4 // Author:
5 //      Marek Habersack <mhabersack@novell.com>
6 //
7 // Copyright (C) 2009 Novell Inc. http://novell.com
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 #if !MOBILE
31 using System;
32 using System.Collections.Generic;
33 using System.ComponentModel;
34 using System.Reflection;
35
36 namespace System.ComponentModel.DataAnnotations
37 {
38         class AssociatedMetadataTypeTypeDescriptor : CustomTypeDescriptor
39         {
40                 Type type;
41                 Type associatedMetadataType;
42                 bool associatedMetadataTypeChecked;
43                 PropertyDescriptorCollection properties;
44                 
45                 Type AssociatedMetadataType {
46                         get {
47                                 if (!associatedMetadataTypeChecked && associatedMetadataType == null)
48                                         associatedMetadataType = FindMetadataType ();
49
50                                 return associatedMetadataType;
51                         }
52                 }
53                 
54                 public AssociatedMetadataTypeTypeDescriptor (ICustomTypeDescriptor parent, Type type)
55                         : this (parent, type, null)
56                 {
57                 }
58
59                 public AssociatedMetadataTypeTypeDescriptor (ICustomTypeDescriptor parent, Type type, Type associatedMetadataType)
60                         : base (parent)
61                 {
62                         this.type = type;
63                         this.associatedMetadataType = associatedMetadataType;
64                 }
65
66                 void CopyAttributes (object[] from, List <Attribute> to)
67                 {
68                         foreach (object o in from) {
69                                 Attribute a = o as Attribute;
70                                 if (a == null)
71                                         continue;
72
73                                 to.Add (a);
74                         }
75                 }
76                 
77                 public override AttributeCollection GetAttributes ()
78                 {
79                         var attributes = new List <Attribute> ();
80                         CopyAttributes (type.GetCustomAttributes (true), attributes);
81                         
82                         Type metaType = AssociatedMetadataType;
83                         if (metaType != null) 
84                                 CopyAttributes (metaType.GetCustomAttributes (true), attributes);
85                         
86                         return new AttributeCollection (attributes.ToArray ());
87                 }
88
89                 public override PropertyDescriptorCollection GetProperties ()
90                 {
91                         // Code partially copied from TypeDescriptor.TypeInfo.GetProperties
92                         if (properties != null)
93                                 return properties;
94
95                         Dictionary <string, MemberInfo> metaMembers = null;
96                         var propertiesHash = new Dictionary <string, bool> (); // name - null
97                         var propertiesList = new List <AssociatedMetadataTypePropertyDescriptor> ();
98                         Type currentType = type;
99                         Type metaType = AssociatedMetadataType;
100
101                         if (metaType != null) {
102                                 metaMembers = new Dictionary <string, MemberInfo> ();
103                                 MemberInfo[] members = metaType.GetMembers (BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
104
105                                 foreach (MemberInfo member in members) {
106                                         switch (member.MemberType) {
107                                                 case MemberTypes.Field:
108                                                 case MemberTypes.Property:
109                                                         break;
110
111                                                 default:
112                                                         continue;
113                                         }
114
115                                         string name = member.Name;
116                                         if (metaMembers.ContainsKey (name))
117                                                 continue;
118
119                                         metaMembers.Add (name, member);
120                                 }
121                         }
122                         
123                         // Getting properties type by type, because in the case of a property in the child type, where
124                         // the "new" keyword is used and also the return type is changed Type.GetProperties returns 
125                         // also the parent property. 
126                         // 
127                         // Note that we also have to preserve the properties order here.
128                         // 
129                         while (currentType != null && currentType != typeof (object)) {
130                                 PropertyInfo[] props = currentType.GetProperties (BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
131                                 foreach (PropertyInfo property in props) {
132                                         string propName = property.Name;
133                                         
134                                         if (property.GetIndexParameters ().Length == 0 && property.CanRead && !propertiesHash.ContainsKey (propName)) {
135                                                 MemberInfo metaMember;
136
137                                                 if (metaMembers != null)
138                                                         metaMembers.TryGetValue (propName, out metaMember);
139                                                 else
140                                                         metaMember = null;
141                                                 propertiesList.Add (new AssociatedMetadataTypePropertyDescriptor (property, metaMember));
142                                                 propertiesHash.Add (propName, true);
143                                         }
144                                 }
145                                 currentType = currentType.BaseType;
146                         }
147
148                         properties = new PropertyDescriptorCollection ((PropertyDescriptor[]) propertiesList.ToArray (), true);
149                         return properties;
150                 }
151                 
152                 Type FindMetadataType ()
153                 {
154                         associatedMetadataTypeChecked = true;
155                         if (type == null)
156                                 return null;
157                         
158                         object[] attrs = type.GetCustomAttributes (typeof (MetadataTypeAttribute), true);
159                         if (attrs == null || attrs.Length == 0)
160                                 return null;
161
162                         var attr = attrs [0] as MetadataTypeAttribute;
163                         if (attr == null)
164                                 return null;
165
166                         return attr.MetadataClassType;
167                 }
168         }
169 }
170 #endif