04e93f76499a9a32b2e7162f6cd8295666a6e273
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Metadata / Edm / MetadataItem.cs
1 //---------------------------------------------------------------------
2 // <copyright file="MetadataItem.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner       Microsoft
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
9 using System;
10 using System.Collections.Generic;
11 using System.Collections.ObjectModel;
12 using System.Diagnostics;
13 using System.Text;
14 using System.Xml.Serialization;
15 using System.Xml.Schema;
16 using System.Xml;
17 using System.Globalization;
18
19 namespace System.Data.Metadata.Edm
20 {
21     /// <summary>
22     /// Represents the base item class for all the metadata
23     /// </summary>
24     public abstract partial class MetadataItem
25     {
26         #region Constructors
27         /// <summary>
28         /// Implementing this internal constructor so that this class can't be derived
29         /// outside this assembly
30         /// </summary>
31         internal MetadataItem()
32         {
33         }
34         internal MetadataItem(MetadataFlags flags)
35         {
36             _flags = flags;
37         }
38         #endregion
39
40         #region Fields
41         [Flags]
42         internal enum MetadataFlags {
43             // GlobalItem
44             None = 0,  // DataSpace flags are off by one so that zero can be the uninitialized state
45             CSpace = 1,   // (1 << 0)
46             OSpace = 2,   // (1 << 1)
47             OCSpace = 3,  // CSpace | OSpace
48             SSpace = 4,   // (1 << 2)
49             CSSpace = 5,  // CSpace | SSpace
50
51             DataSpace = OSpace | CSpace | SSpace | OCSpace | CSSpace,
52
53             // MetadataItem
54             Readonly = (1 << 3),
55
56             // EdmType
57             IsAbstract = (1 << 4),
58
59             // FunctionParameter
60             In = (1 << 9),
61             Out = (1 << 10),
62             InOut = In | Out,
63             ReturnValue = (1 << 11),
64
65             ParameterMode = (In | Out | InOut | ReturnValue),
66         }
67         private MetadataFlags _flags;
68         private object _flagsLock = new object();
69         private MetadataCollection<MetadataProperty> _itemAttributes;
70         private Documentation _documentation;
71         #endregion
72
73         #region Properties
74
75         /// <summary>
76         /// Returns the kind of the type
77         /// </summary>
78         public abstract BuiltInTypeKind BuiltInTypeKind
79         {
80             get;
81         }
82
83         /// <summary>
84         /// List of item attributes on this type
85         /// </summary>
86         [MetadataProperty(BuiltInTypeKind.MetadataProperty, true)]
87         public ReadOnlyMetadataCollection<MetadataProperty> MetadataProperties
88         {
89             get
90             {
91                 if (null == _itemAttributes)
92                 {
93                     MetadataPropertyCollection itemAttributes = new MetadataPropertyCollection(this);
94                     if (IsReadOnly)
95                     {
96                         itemAttributes.SetReadOnly();
97                     }
98                     System.Threading.Interlocked.CompareExchange<MetadataCollection<MetadataProperty>>(
99                         ref _itemAttributes, itemAttributes, null);
100                 }
101                 return _itemAttributes.AsReadOnlyMetadataCollection();
102             }
103         }
104
105         /// <summary>
106         /// List of item attributes on this type
107         /// </summary>
108         internal MetadataCollection<MetadataProperty> RawMetadataProperties
109         {
110             get
111             {
112                 return _itemAttributes;
113             }
114         }
115
116         /// <summary>
117         /// List of item attributes on this type
118         /// </summary>
119         public Documentation Documentation
120         {
121             get
122             {
123                 return _documentation; 
124             }
125             set
126             {
127                 _documentation = value;
128             }
129         }
130
131         /// <summary>
132         /// Identity of the item
133         /// </summary>
134         internal abstract String Identity { get; }
135
136         /// <summary>
137         /// Just checks for identities to be equal
138         /// </summary>
139         /// <param name="item"></param>
140         /// <returns></returns>
141         internal virtual bool EdmEquals(MetadataItem item)
142         {
143             return ((null != item) &&
144                     ((this == item) || // same reference
145                      (this.BuiltInTypeKind == item.BuiltInTypeKind &&
146                       this.Identity == item.Identity)));
147         }
148
149         /// <summary>
150         /// Returns true if this item is not-changeable. Otherwise returns false.
151         /// </summary>
152         internal bool IsReadOnly
153         {
154             get
155             {
156                 return GetFlag(MetadataFlags.Readonly);
157             }
158         }
159         #endregion
160
161         #region Methods
162         /// <summary>
163         /// Validates the types and sets the readOnly property to true. Once the type is set to readOnly,
164         /// it can never be changed. 
165         /// </summary>
166         internal virtual void SetReadOnly()
167         {
168             if (!IsReadOnly)
169             {
170                 if (null != _itemAttributes)
171                 {
172                     _itemAttributes.SetReadOnly();
173                 }
174                 SetFlag(MetadataFlags.Readonly, true);
175             }
176         }
177
178         /// <summary>
179         /// Builds identity string for this item. By default, the method calls the identity property.
180         /// </summary>
181         /// <param name="builder"></param>
182         internal virtual void BuildIdentity(StringBuilder builder)
183         {
184             builder.Append(this.Identity);
185         }
186
187         /// <summary>
188         /// Adds the given metadata property to the metadata property collection
189         /// </summary>
190         /// <param name="metadataProperty"></param>
191         internal void AddMetadataProperties(List<MetadataProperty> metadataProperties)
192         {
193             this.MetadataProperties.Source.AtomicAddRange(metadataProperties);
194         }
195         #endregion
196
197         #region MetadataFlags
198         internal DataSpace GetDataSpace()
199         {
200             switch (_flags & MetadataFlags.DataSpace)
201             {
202                 default: return (DataSpace)(-1);
203                 case MetadataFlags.CSpace: return DataSpace.CSpace;
204                 case MetadataFlags.OSpace: return DataSpace.OSpace;
205                 case MetadataFlags.SSpace: return DataSpace.SSpace;
206                 case MetadataFlags.OCSpace: return DataSpace.OCSpace;
207                 case MetadataFlags.CSSpace: return DataSpace.CSSpace;
208             }
209         }
210         internal void SetDataSpace(DataSpace space)
211         {
212             _flags = (_flags & ~MetadataFlags.DataSpace) | (MetadataFlags.DataSpace & Convert(space));
213         }
214         private static MetadataFlags Convert(DataSpace space) {
215             switch (space)
216             {
217                 default: return MetadataFlags.None; // invalid
218                 case DataSpace.CSpace: return MetadataFlags.CSpace;
219                 case DataSpace.OSpace: return MetadataFlags.OSpace;
220                 case DataSpace.SSpace: return MetadataFlags.SSpace;
221                 case DataSpace.OCSpace: return MetadataFlags.OCSpace;
222                 case DataSpace.CSSpace: return MetadataFlags.CSSpace;
223             }
224         }
225
226         internal ParameterMode GetParameterMode()
227         {
228             switch (_flags & MetadataFlags.ParameterMode)
229             {
230                 default: return (ParameterMode)(-1); // invalid
231                 case MetadataFlags.In: return ParameterMode.In;
232                 case MetadataFlags.Out: return ParameterMode.Out;
233                 case MetadataFlags.InOut: return ParameterMode.InOut;
234                 case MetadataFlags.ReturnValue: return ParameterMode.ReturnValue;
235             }
236         }
237         internal void SetParameterMode(ParameterMode mode)
238         {
239             _flags = (_flags & ~MetadataFlags.ParameterMode) | (MetadataFlags.ParameterMode & Convert(mode));
240         }
241         private static MetadataFlags Convert(ParameterMode mode)
242         {
243             switch (mode)
244             {
245                 default: return MetadataFlags.ParameterMode; // invalid
246                 case ParameterMode.In: return MetadataFlags.In;
247                 case ParameterMode.Out: return MetadataFlags.Out;
248                 case ParameterMode.InOut: return MetadataFlags.InOut;
249                 case ParameterMode.ReturnValue: return MetadataFlags.ReturnValue;
250             }
251         }
252
253         internal bool GetFlag(MetadataFlags flag)
254         {
255             return (flag == (_flags & flag)); 
256         }
257         internal void SetFlag(MetadataFlags flag, bool value)
258         {
259             if ((flag & MetadataFlags.Readonly) == MetadataFlags.Readonly)
260             {
261                 Debug.Assert(System.Convert.ToInt32(flag & ~MetadataFlags.Readonly,CultureInfo.InvariantCulture) == 0,
262                             "SetFlag() invoked with Readonly and additional flags.");
263             }
264
265             lock (_flagsLock)
266             {
267                 // an attempt to set the ReadOnly flag on a MetadataItem that is already read-only
268                 // is a no-op
269                 //
270                 if (IsReadOnly && ((flag & MetadataFlags.Readonly) == MetadataFlags.Readonly))
271                 {
272                     return;
273                 }
274
275                 Util.ThrowIfReadOnly(this);
276                 if (value)
277                 {
278                     _flags |= flag;
279                 }
280                 else
281                 {
282                     _flags &= ~flag;
283                 }
284             }
285         }
286         #endregion
287     }
288 }