Merge pull request #1936 from esdrubal/DotNetRelativeOrAbsolute
[mono.git] / mcs / class / corlib / System.Runtime.Remoting.Contexts / Context.cs
1 //
2 // System.Runtime.Remoting.Contexts.Context..cs
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Lluis Sanchez Gual (lluis@ideary.com)
7 //   Patrik Torstensson
8 //
9 // (C) Ximian, Inc.  http://www.ximian.com
10 //
11
12 //
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34
35 using System.Collections;
36 using System.Collections.Generic;
37 using System.Threading;
38 using System.Runtime.Remoting;
39 using System.Runtime.Remoting.Proxies;
40 using System.Runtime.Remoting.Activation;
41 using System.Runtime.Remoting.Messaging;
42 using System.Runtime.Remoting.Lifetime;
43 using System.Runtime.CompilerServices;
44 using System.Runtime.InteropServices;
45
46
47 namespace System.Runtime.Remoting.Contexts {
48
49         [System.Runtime.InteropServices.ComVisible (true)]
50         [StructLayout (LayoutKind.Sequential)]
51         public class Context 
52         {
53 #pragma warning disable 169, 414
54                 #region Sync with domain-internals.h
55                 int domain_id;
56                 int context_id;
57                 UIntPtr static_data; /* GC-tracked */
58                 #endregion
59 #pragma warning restore 169, 414
60
61                 // Name is significant; used by the runtime.
62                 [ContextStatic]
63                 static object[] local_slots;
64
65                 // Default server context sink chain
66                 static IMessageSink default_server_context_sink;
67
68                 // The sink chain that has to be used by all calls entering the context
69                 IMessageSink server_context_sink_chain = null;
70
71                 // The sink chain that has to be used by all calls exiting the context
72                 IMessageSink client_context_sink_chain = null;
73
74                 List<IContextProperty> context_properties;
75 //              bool frozen;
76                 
77                 static int global_count;
78
79                 volatile LocalDataStoreHolder _localDataStore;
80
81                 static LocalDataStoreMgr _localDataStoreMgr = new LocalDataStoreMgr();
82
83                 static DynamicPropertyCollection global_dynamic_properties;
84                 DynamicPropertyCollection context_dynamic_properties;
85                 ContextCallbackObject callback_object = null;
86
87                 [MethodImpl (MethodImplOptions.InternalCall)]
88                 extern static void RegisterContext (Context ctx);
89
90                 [MethodImpl (MethodImplOptions.InternalCall)]
91                 extern static void ReleaseContext (Context ctx);
92                 
93                 public Context ()
94                 {
95                         domain_id = Thread.GetDomainID();
96                         context_id = Interlocked.Increment (ref global_count);
97
98                         RegisterContext (this);
99                 }
100
101                 ~Context ()
102                 {
103                         ReleaseContext (this);
104                 }
105
106                 public static Context DefaultContext {
107                         get {
108                                 return AppDomain.InternalGetDefaultContext ();
109                         }
110                 }
111
112                 public virtual int ContextID {
113                         get {
114                                 return context_id;
115                         }
116                 }
117
118                 public virtual IContextProperty[] ContextProperties
119                 {
120                         get 
121                         {
122                                 if (context_properties == null)
123                                         return new IContextProperty[0];
124                                 
125                                 return context_properties.ToArray ();
126                         }
127                 }
128                 
129                 internal bool IsDefaultContext
130                 {
131                         get { return context_id == 0; }
132                 }
133
134                 internal bool NeedsContextSink
135                 {
136                         get {
137                                 return context_id != 0 || 
138                                         (global_dynamic_properties != null && global_dynamic_properties.HasProperties) || 
139                                         (context_dynamic_properties != null && context_dynamic_properties.HasProperties);
140                         }
141                 }
142
143                 public static bool RegisterDynamicProperty(IDynamicProperty prop, ContextBoundObject obj, Context ctx)
144                 {
145                         DynamicPropertyCollection col = GetDynamicPropertyCollection (obj, ctx);
146                         return col.RegisterDynamicProperty (prop);
147                 }
148
149                 public static bool UnregisterDynamicProperty(string name, ContextBoundObject obj, Context ctx)
150                 {
151                         DynamicPropertyCollection col = GetDynamicPropertyCollection (obj, ctx);
152                         return col.UnregisterDynamicProperty (name);
153                 }
154                 
155                 static DynamicPropertyCollection GetDynamicPropertyCollection(ContextBoundObject obj, Context ctx)
156                 {
157                         if (ctx == null && obj != null)
158                         {
159                                 if (RemotingServices.IsTransparentProxy(obj))
160                                 {
161                                         RealProxy rp = RemotingServices.GetRealProxy (obj);
162                                         return rp.ObjectIdentity.ClientDynamicProperties;
163                                 }
164                                 else
165                                 {
166 #if FEATURE_REMOTING
167                                         return obj.ObjectIdentity.ServerDynamicProperties;
168 #else
169                                         throw new NotSupportedException ();
170 #endif                                  
171                                 }
172                         }
173                         else if (ctx != null && obj == null)
174                         {
175                                 if (ctx.context_dynamic_properties == null) ctx.context_dynamic_properties = new DynamicPropertyCollection ();
176                                 return ctx.context_dynamic_properties;
177                         }
178                         else if (ctx == null && obj == null)
179                         {
180                                 if (global_dynamic_properties == null) global_dynamic_properties = new DynamicPropertyCollection ();
181                                 return global_dynamic_properties;
182                         }
183                         else
184                                 throw new ArgumentException ("Either obj or ctx must be null");
185                 }
186                 
187                 internal static void NotifyGlobalDynamicSinks  (bool start, IMessage req_msg, bool client_site, bool async)
188                 {
189                         if (global_dynamic_properties != null && global_dynamic_properties.HasProperties) 
190                                 global_dynamic_properties.NotifyMessage (start, req_msg, client_site, async);
191                 }
192
193                 internal static bool HasGlobalDynamicSinks
194                 {
195                         get { return (global_dynamic_properties != null && global_dynamic_properties.HasProperties); }
196                 }
197
198                 internal void NotifyDynamicSinks  (bool start, IMessage req_msg, bool client_site, bool async)
199                 {
200                         if (context_dynamic_properties != null && context_dynamic_properties.HasProperties) 
201                                 context_dynamic_properties.NotifyMessage (start, req_msg, client_site, async);
202                 }
203
204                 internal bool HasDynamicSinks
205                 {
206                         get { return (context_dynamic_properties != null && context_dynamic_properties.HasProperties); }
207                 }
208
209                 internal bool HasExitSinks
210                 {
211                         get
212                         {
213                                 // Needs to go through the client context sink if there are custom
214                                 // client context or dynamic sinks.
215
216                                 return ( !(GetClientContextSinkChain() is ClientContextTerminatorSink) || HasDynamicSinks || HasGlobalDynamicSinks);
217                         }
218                 }
219
220                 public virtual IContextProperty GetProperty (string name)
221                 {
222                         if (context_properties == null)
223                                 return null;
224
225                         foreach (IContextProperty p in context_properties)
226                                 if (p.Name == name)
227                                         return p;
228                         
229                         return null;
230                 }
231
232                 public virtual void SetProperty (IContextProperty prop)
233                 {
234                         if (prop == null)
235                                 throw new ArgumentNullException ("IContextProperty");
236                         if (this == DefaultContext)
237                                 throw new InvalidOperationException ("Can not add properties to " +
238                                                                      "default context");
239 //                      if (frozen)
240 //                              throw new InvalidOperationException ("Context is Frozen");
241                         
242                         if (context_properties == null)
243                                 context_properties = new List<IContextProperty> ();
244
245                         context_properties.Add (prop);
246                 }
247
248                 public virtual void Freeze ()
249                 {
250                         if (context_properties != null)
251                         {
252                                 foreach (IContextProperty prop in context_properties)
253                                         prop.Freeze (this);
254                         }
255                 }
256
257                 public override string ToString()
258                 {
259                         return "ContextID: " + context_id;
260                 }
261
262                 internal IMessageSink GetServerContextSinkChain()
263                 {
264                         if (server_context_sink_chain == null)
265                         {
266                                 if (default_server_context_sink == null)
267                                         default_server_context_sink = new ServerContextTerminatorSink();
268
269                                 server_context_sink_chain = default_server_context_sink;
270
271                                 if (context_properties != null) {
272                                         // Enumerate in reverse order
273                                         for (int n = context_properties.Count-1; n>=0; n--) {
274                                                 IContributeServerContextSink contributor = context_properties[n] as IContributeServerContextSink;
275                                                 if (contributor != null)
276                                                         server_context_sink_chain = contributor.GetServerContextSink (server_context_sink_chain);
277                                         }
278                                 }
279                         }
280                         return server_context_sink_chain;
281                 }
282
283                 internal IMessageSink GetClientContextSinkChain()
284                 {
285                         if (client_context_sink_chain == null)
286                         {
287                                 client_context_sink_chain = new ClientContextTerminatorSink (this);
288
289                                 if (context_properties != null) {
290                                         foreach (IContextProperty prop in context_properties) {
291                                                 IContributeClientContextSink contributor = prop as IContributeClientContextSink;
292                                                 if (contributor != null)
293                                                         client_context_sink_chain = contributor.GetClientContextSink (client_context_sink_chain);
294                                         }
295                                 }
296                         }
297                         return client_context_sink_chain;
298                 }
299
300                 internal IMessageSink CreateServerObjectSinkChain (MarshalByRefObject obj, bool forceInternalExecute)
301                 {
302                         IMessageSink objectSink = new StackBuilderSink (obj, forceInternalExecute);
303                         objectSink = new ServerObjectTerminatorSink (objectSink);
304                         objectSink = new Lifetime.LeaseSink (objectSink);
305
306                         if (context_properties != null)
307                         {
308                                 // Contribute object sinks in reverse order
309                                 for (int n = context_properties.Count-1; n >= 0; n--)
310                                 {
311                                         IContextProperty prop = (IContextProperty) context_properties[n];
312                                         IContributeObjectSink contributor = prop as IContributeObjectSink;
313                                         if (contributor != null)
314                                                 objectSink = contributor.GetObjectSink (obj, objectSink);
315                                 }
316                         }
317                         return objectSink;
318                 }
319
320                 internal IMessageSink CreateEnvoySink (MarshalByRefObject serverObject)
321                 {
322                         IMessageSink sink = EnvoyTerminatorSink.Instance;
323                         if (context_properties != null)
324                         {
325                                 foreach (IContextProperty prop in context_properties)
326                                 {
327                                         IContributeEnvoySink contributor = prop as IContributeEnvoySink;
328                                         if (contributor != null)
329                                                 sink = contributor.GetEnvoySink (serverObject, sink);
330                                 }
331                         }
332                         return sink;
333                 }
334
335                 internal static Context SwitchToContext (Context newContext)
336                 {
337                         return AppDomain.InternalSetContext (newContext);
338                 }
339
340                 internal static Context CreateNewContext (IConstructionCallMessage msg)
341                 {
342                         // Create the new context
343
344                         Context newContext = new Context();
345
346                         foreach (IContextProperty prop in msg.ContextProperties)
347                         {
348                                 if (newContext.GetProperty (prop.Name) == null)
349                                         newContext.SetProperty (prop);
350                         }
351                         newContext.Freeze();
352
353
354                         // Ask each context property whether the new context is OK
355
356                         foreach (IContextProperty prop in msg.ContextProperties)
357                                 if (!prop.IsNewContextOK (newContext)) 
358                                         throw new RemotingException("A context property did not approve the candidate context for activating the object");
359
360                         return newContext;
361                 }
362                 
363                 public void DoCallBack (CrossContextDelegate deleg)
364                 {
365                         lock (this)
366                         {
367                                 if (callback_object == null) {
368                                         Context oldContext = Context.SwitchToContext (this);
369                                         callback_object = new ContextCallbackObject ();
370                                         Context.SwitchToContext (oldContext);
371                                 }
372                         }
373                         
374                         callback_object.DoCallBack (deleg);
375                 }
376
377                 private LocalDataStore MyLocalStore 
378                 {
379                         get 
380                         { 
381                                 if (_localDataStore == null)
382                                 {
383                                         // It's OK to lock the manager here because it is going to lock
384                                         // itself anyway.
385                                         lock (_localDataStoreMgr)
386                                         {
387                                                 if (_localDataStore == null)
388                                                 {
389                                                         // The local store has not yet been created for this thread.
390                                                         _localDataStore = _localDataStoreMgr.CreateLocalDataStore();
391                                                 }
392                                         }
393                                 }
394                                 return _localDataStore.Store;
395                         }
396                 }
397
398                 public static LocalDataStoreSlot AllocateDataSlot ()
399                 {
400                         return _localDataStoreMgr.AllocateDataSlot ();
401                 }
402
403                 public static LocalDataStoreSlot AllocateNamedDataSlot (string name)
404                 {
405                         return _localDataStoreMgr.AllocateNamedDataSlot (name);
406                 }
407
408                 public static void FreeNamedDataSlot (string name)
409                 {
410                         _localDataStoreMgr.FreeNamedDataSlot (name);
411                 }
412
413                 public static LocalDataStoreSlot GetNamedDataSlot (string name)
414                 {
415                         return _localDataStoreMgr.GetNamedDataSlot (name);
416                 }
417
418                 public static object GetData (LocalDataStoreSlot slot)
419                 {
420                         return Thread.CurrentContext.MyLocalStore.GetData (slot);
421                 }
422
423                 public static void SetData (LocalDataStoreSlot slot, object data)
424                 {
425                         Thread.CurrentContext.MyLocalStore.SetData (slot, data);
426                 }
427         }
428
429         class DynamicPropertyCollection
430         {
431                 ArrayList _properties = new ArrayList();
432
433                 class DynamicPropertyReg
434                 {
435                         public IDynamicProperty Property;
436                         public IDynamicMessageSink Sink;
437                 }
438
439                 public bool HasProperties
440                 {
441                         get { return _properties.Count > 0; }
442                 }
443
444                 public bool RegisterDynamicProperty(IDynamicProperty prop)
445                 {
446                         lock (this)
447                         {
448                                 if (FindProperty (prop.Name) != -1) 
449                                         throw new InvalidOperationException ("Another property by this name already exists");
450
451                                 // Make a copy, do not interfere with threads running dynamic sinks
452                                 ArrayList newProps = new ArrayList (_properties);
453
454                                 DynamicPropertyReg reg = new DynamicPropertyReg();
455                                 reg.Property = prop;
456                                 IContributeDynamicSink contributor = prop as IContributeDynamicSink;
457                                 if (contributor != null) reg.Sink = contributor.GetDynamicSink ();
458                                 newProps.Add (reg);
459
460                                 _properties = newProps;
461
462                                 return true;    // When should be false?
463                         }
464                 }
465
466                 public bool UnregisterDynamicProperty(string name)
467                 {
468                         lock (this)
469                         {
470                                 int i = FindProperty (name);
471                                 if (i == -1) throw new RemotingException ("A property with the name " + name + " was not found");
472
473                                 _properties.RemoveAt (i);
474                                 return true;    // When should be false?
475                         }
476                 }
477
478                 public void NotifyMessage (bool start, IMessage msg, bool client_site, bool async)
479                 {
480                         ArrayList props = _properties;
481                         if (start)
482                         {
483                                 foreach (DynamicPropertyReg reg in props)
484                                         if (reg.Sink != null) reg.Sink.ProcessMessageStart (msg, client_site, async);
485                         }
486                         else
487                         {
488                                 foreach (DynamicPropertyReg reg in props)
489                                         if (reg.Sink != null) reg.Sink.ProcessMessageFinish (msg, client_site, async);
490                         }
491                 }
492
493                 int FindProperty (string name)
494                 {
495                         for (int n=0; n<_properties.Count; n++)
496                                 if (((DynamicPropertyReg)_properties[n]).Property.Name == name)
497                                         return n;
498                         return -1;
499                 }
500         }
501         
502         class ContextCallbackObject: ContextBoundObject
503         {
504                 public void DoCallBack (CrossContextDelegate deleg)
505                 {
506                 }
507         }
508 }