2 // System.Runtime.Remoting.Contexts.Context..cs
5 // Miguel de Icaza (miguel@ximian.com)
6 // Lluis Sanchez Gual (lluis@ideary.com)
9 // (C) Ximian, Inc. http://www.ximian.com
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
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.
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;
47 namespace System.Runtime.Remoting.Contexts {
49 [System.Runtime.InteropServices.ComVisible (true)]
50 [StructLayout (LayoutKind.Sequential)]
53 #pragma warning disable 169, 414
54 #region Sync with domain-internals.h
57 UIntPtr static_data; /* GC-tracked */
59 #pragma warning restore 169, 414
61 // Name is significant; used by the runtime.
63 static object[] local_slots;
65 // Default server context sink chain
66 static IMessageSink default_server_context_sink;
68 // The sink chain that has to be used by all calls entering the context
69 IMessageSink server_context_sink_chain = null;
71 // The sink chain that has to be used by all calls exiting the context
72 IMessageSink client_context_sink_chain = null;
74 List<IContextProperty> context_properties;
77 static int global_count;
79 volatile LocalDataStoreHolder _localDataStore;
81 static LocalDataStoreMgr _localDataStoreMgr = new LocalDataStoreMgr();
83 static DynamicPropertyCollection global_dynamic_properties;
84 DynamicPropertyCollection context_dynamic_properties;
85 ContextCallbackObject callback_object = null;
87 [MethodImpl (MethodImplOptions.InternalCall)]
88 extern static void RegisterContext (Context ctx);
90 [MethodImpl (MethodImplOptions.InternalCall)]
91 extern static void ReleaseContext (Context ctx);
95 domain_id = Thread.GetDomainID();
96 context_id = Interlocked.Increment (ref global_count);
98 RegisterContext (this);
103 ReleaseContext (this);
106 public static Context DefaultContext {
108 return AppDomain.InternalGetDefaultContext ();
112 public virtual int ContextID {
118 public virtual IContextProperty[] ContextProperties
122 if (context_properties == null)
123 return new IContextProperty[0];
125 return context_properties.ToArray ();
129 internal bool IsDefaultContext
131 get { return context_id == 0; }
134 internal bool NeedsContextSink
137 return context_id != 0 ||
138 (global_dynamic_properties != null && global_dynamic_properties.HasProperties) ||
139 (context_dynamic_properties != null && context_dynamic_properties.HasProperties);
143 public static bool RegisterDynamicProperty(IDynamicProperty prop, ContextBoundObject obj, Context ctx)
145 DynamicPropertyCollection col = GetDynamicPropertyCollection (obj, ctx);
146 return col.RegisterDynamicProperty (prop);
149 public static bool UnregisterDynamicProperty(string name, ContextBoundObject obj, Context ctx)
151 DynamicPropertyCollection col = GetDynamicPropertyCollection (obj, ctx);
152 return col.UnregisterDynamicProperty (name);
155 static DynamicPropertyCollection GetDynamicPropertyCollection(ContextBoundObject obj, Context ctx)
157 if (ctx == null && obj != null)
159 if (RemotingServices.IsTransparentProxy(obj))
161 RealProxy rp = RemotingServices.GetRealProxy (obj);
162 return rp.ObjectIdentity.ClientDynamicProperties;
167 return obj.ObjectIdentity.ServerDynamicProperties;
169 throw new NotSupportedException ();
173 else if (ctx != null && obj == null)
175 if (ctx.context_dynamic_properties == null) ctx.context_dynamic_properties = new DynamicPropertyCollection ();
176 return ctx.context_dynamic_properties;
178 else if (ctx == null && obj == null)
180 if (global_dynamic_properties == null) global_dynamic_properties = new DynamicPropertyCollection ();
181 return global_dynamic_properties;
184 throw new ArgumentException ("Either obj or ctx must be null");
187 internal static void NotifyGlobalDynamicSinks (bool start, IMessage req_msg, bool client_site, bool async)
189 if (global_dynamic_properties != null && global_dynamic_properties.HasProperties)
190 global_dynamic_properties.NotifyMessage (start, req_msg, client_site, async);
193 internal static bool HasGlobalDynamicSinks
195 get { return (global_dynamic_properties != null && global_dynamic_properties.HasProperties); }
198 internal void NotifyDynamicSinks (bool start, IMessage req_msg, bool client_site, bool async)
200 if (context_dynamic_properties != null && context_dynamic_properties.HasProperties)
201 context_dynamic_properties.NotifyMessage (start, req_msg, client_site, async);
204 internal bool HasDynamicSinks
206 get { return (context_dynamic_properties != null && context_dynamic_properties.HasProperties); }
209 internal bool HasExitSinks
213 // Needs to go through the client context sink if there are custom
214 // client context or dynamic sinks.
216 return ( !(GetClientContextSinkChain() is ClientContextTerminatorSink) || HasDynamicSinks || HasGlobalDynamicSinks);
220 public virtual IContextProperty GetProperty (string name)
222 if (context_properties == null)
225 foreach (IContextProperty p in context_properties)
232 public virtual void SetProperty (IContextProperty prop)
235 throw new ArgumentNullException ("IContextProperty");
236 if (this == DefaultContext)
237 throw new InvalidOperationException ("Can not add properties to " +
240 // throw new InvalidOperationException ("Context is Frozen");
242 if (context_properties == null)
243 context_properties = new List<IContextProperty> ();
245 context_properties.Add (prop);
248 public virtual void Freeze ()
250 if (context_properties != null)
252 foreach (IContextProperty prop in context_properties)
257 public override string ToString()
259 return "ContextID: " + context_id;
262 internal IMessageSink GetServerContextSinkChain()
264 if (server_context_sink_chain == null)
266 if (default_server_context_sink == null)
267 default_server_context_sink = new ServerContextTerminatorSink();
269 server_context_sink_chain = default_server_context_sink;
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);
280 return server_context_sink_chain;
283 internal IMessageSink GetClientContextSinkChain()
285 if (client_context_sink_chain == null)
287 client_context_sink_chain = new ClientContextTerminatorSink (this);
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);
297 return client_context_sink_chain;
300 internal IMessageSink CreateServerObjectSinkChain (MarshalByRefObject obj, bool forceInternalExecute)
302 IMessageSink objectSink = new StackBuilderSink (obj, forceInternalExecute);
303 objectSink = new ServerObjectTerminatorSink (objectSink);
304 objectSink = new Lifetime.LeaseSink (objectSink);
306 if (context_properties != null)
308 // Contribute object sinks in reverse order
309 for (int n = context_properties.Count-1; n >= 0; n--)
311 IContextProperty prop = (IContextProperty) context_properties[n];
312 IContributeObjectSink contributor = prop as IContributeObjectSink;
313 if (contributor != null)
314 objectSink = contributor.GetObjectSink (obj, objectSink);
320 internal IMessageSink CreateEnvoySink (MarshalByRefObject serverObject)
322 IMessageSink sink = EnvoyTerminatorSink.Instance;
323 if (context_properties != null)
325 foreach (IContextProperty prop in context_properties)
327 IContributeEnvoySink contributor = prop as IContributeEnvoySink;
328 if (contributor != null)
329 sink = contributor.GetEnvoySink (serverObject, sink);
335 internal static Context SwitchToContext (Context newContext)
337 return AppDomain.InternalSetContext (newContext);
340 internal static Context CreateNewContext (IConstructionCallMessage msg)
342 // Create the new context
344 Context newContext = new Context();
346 foreach (IContextProperty prop in msg.ContextProperties)
348 if (newContext.GetProperty (prop.Name) == null)
349 newContext.SetProperty (prop);
354 // Ask each context property whether the new context is OK
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");
363 public void DoCallBack (CrossContextDelegate deleg)
367 if (callback_object == null) {
368 Context oldContext = Context.SwitchToContext (this);
369 callback_object = new ContextCallbackObject ();
370 Context.SwitchToContext (oldContext);
374 callback_object.DoCallBack (deleg);
377 private LocalDataStore MyLocalStore
381 if (_localDataStore == null)
383 // It's OK to lock the manager here because it is going to lock
385 lock (_localDataStoreMgr)
387 if (_localDataStore == null)
389 // The local store has not yet been created for this thread.
390 _localDataStore = _localDataStoreMgr.CreateLocalDataStore();
394 return _localDataStore.Store;
398 public static LocalDataStoreSlot AllocateDataSlot ()
400 return _localDataStoreMgr.AllocateDataSlot ();
403 public static LocalDataStoreSlot AllocateNamedDataSlot (string name)
405 return _localDataStoreMgr.AllocateNamedDataSlot (name);
408 public static void FreeNamedDataSlot (string name)
410 _localDataStoreMgr.FreeNamedDataSlot (name);
413 public static LocalDataStoreSlot GetNamedDataSlot (string name)
415 return _localDataStoreMgr.GetNamedDataSlot (name);
418 public static object GetData (LocalDataStoreSlot slot)
420 return Thread.CurrentContext.MyLocalStore.GetData (slot);
423 public static void SetData (LocalDataStoreSlot slot, object data)
425 Thread.CurrentContext.MyLocalStore.SetData (slot, data);
429 class DynamicPropertyCollection
431 ArrayList _properties = new ArrayList();
433 class DynamicPropertyReg
435 public IDynamicProperty Property;
436 public IDynamicMessageSink Sink;
439 public bool HasProperties
441 get { return _properties.Count > 0; }
444 public bool RegisterDynamicProperty(IDynamicProperty prop)
448 if (FindProperty (prop.Name) != -1)
449 throw new InvalidOperationException ("Another property by this name already exists");
451 // Make a copy, do not interfere with threads running dynamic sinks
452 ArrayList newProps = new ArrayList (_properties);
454 DynamicPropertyReg reg = new DynamicPropertyReg();
456 IContributeDynamicSink contributor = prop as IContributeDynamicSink;
457 if (contributor != null) reg.Sink = contributor.GetDynamicSink ();
460 _properties = newProps;
462 return true; // When should be false?
466 public bool UnregisterDynamicProperty(string name)
470 int i = FindProperty (name);
471 if (i == -1) throw new RemotingException ("A property with the name " + name + " was not found");
473 _properties.RemoveAt (i);
474 return true; // When should be false?
478 public void NotifyMessage (bool start, IMessage msg, bool client_site, bool async)
480 ArrayList props = _properties;
483 foreach (DynamicPropertyReg reg in props)
484 if (reg.Sink != null) reg.Sink.ProcessMessageStart (msg, client_site, async);
488 foreach (DynamicPropertyReg reg in props)
489 if (reg.Sink != null) reg.Sink.ProcessMessageFinish (msg, client_site, async);
493 int FindProperty (string name)
495 for (int n=0; n<_properties.Count; n++)
496 if (((DynamicPropertyReg)_properties[n]).Property.Name == name)
502 class ContextCallbackObject: ContextBoundObject
504 public void DoCallBack (CrossContextDelegate deleg)