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.InteropServices;
46 namespace System.Runtime.Remoting.Contexts {
48 [System.Runtime.InteropServices.ComVisible (true)]
49 [StructLayout (LayoutKind.Sequential)]
52 #pragma warning disable 169, 414
53 #region Sync with domain-internals.h
56 UIntPtr static_data; /* GC-tracked */
58 #pragma warning restore 169, 414
60 // Default server context sink chain
61 static IMessageSink default_server_context_sink;
63 // The sink chain that has to be used by all calls entering the context
64 IMessageSink server_context_sink_chain = null;
66 // The sink chain that has to be used by all calls exiting the context
67 IMessageSink client_context_sink_chain = null;
70 List<IContextProperty> context_properties;
73 static int global_count;
75 /* Wrap this in a nested class so its not constructed during shutdown */
77 public static Hashtable namedSlots = new Hashtable ();
80 static DynamicPropertyCollection global_dynamic_properties;
81 DynamicPropertyCollection context_dynamic_properties;
82 ContextCallbackObject callback_object = null;
86 domain_id = Thread.GetDomainID();
87 context_id = 1 + global_count++;
94 public static Context DefaultContext {
96 return AppDomain.InternalGetDefaultContext ();
100 public virtual int ContextID {
106 public virtual IContextProperty[] ContextProperties
110 if (context_properties == null)
111 return new IContextProperty[0];
113 return context_properties.ToArray ();
117 internal bool IsDefaultContext
119 get { return context_id == 0; }
122 internal bool NeedsContextSink
125 return context_id != 0 ||
126 (global_dynamic_properties != null && global_dynamic_properties.HasProperties) ||
127 (context_dynamic_properties != null && context_dynamic_properties.HasProperties);
131 public static bool RegisterDynamicProperty(IDynamicProperty prop, ContextBoundObject obj, Context ctx)
133 DynamicPropertyCollection col = GetDynamicPropertyCollection (obj, ctx);
134 return col.RegisterDynamicProperty (prop);
137 public static bool UnregisterDynamicProperty(string name, ContextBoundObject obj, Context ctx)
139 DynamicPropertyCollection col = GetDynamicPropertyCollection (obj, ctx);
140 return col.UnregisterDynamicProperty (name);
143 static DynamicPropertyCollection GetDynamicPropertyCollection(ContextBoundObject obj, Context ctx)
145 if (ctx == null && obj != null)
147 if (RemotingServices.IsTransparentProxy(obj))
149 RealProxy rp = RemotingServices.GetRealProxy (obj);
150 return rp.ObjectIdentity.ClientDynamicProperties;
153 return obj.ObjectIdentity.ServerDynamicProperties;
155 else if (ctx != null && obj == null)
157 if (ctx.context_dynamic_properties == null) ctx.context_dynamic_properties = new DynamicPropertyCollection ();
158 return ctx.context_dynamic_properties;
160 else if (ctx == null && obj == null)
162 if (global_dynamic_properties == null) global_dynamic_properties = new DynamicPropertyCollection ();
163 return global_dynamic_properties;
166 throw new ArgumentException ("Either obj or ctx must be null");
169 internal static void NotifyGlobalDynamicSinks (bool start, IMessage req_msg, bool client_site, bool async)
171 if (global_dynamic_properties != null && global_dynamic_properties.HasProperties)
172 global_dynamic_properties.NotifyMessage (start, req_msg, client_site, async);
175 internal static bool HasGlobalDynamicSinks
177 get { return (global_dynamic_properties != null && global_dynamic_properties.HasProperties); }
180 internal void NotifyDynamicSinks (bool start, IMessage req_msg, bool client_site, bool async)
182 if (context_dynamic_properties != null && context_dynamic_properties.HasProperties)
183 context_dynamic_properties.NotifyMessage (start, req_msg, client_site, async);
186 internal bool HasDynamicSinks
188 get { return (context_dynamic_properties != null && context_dynamic_properties.HasProperties); }
191 internal bool HasExitSinks
195 // Needs to go through the client context sink if there are custom
196 // client context or dynamic sinks.
198 return ( !(GetClientContextSinkChain() is ClientContextTerminatorSink) || HasDynamicSinks || HasGlobalDynamicSinks);
202 public virtual IContextProperty GetProperty (string name)
204 if (context_properties == null)
207 foreach (IContextProperty p in context_properties)
214 public virtual void SetProperty (IContextProperty prop)
217 throw new ArgumentNullException ("IContextProperty");
218 if (this == DefaultContext)
219 throw new InvalidOperationException ("Can not add properties to " +
222 // throw new InvalidOperationException ("Context is Frozen");
224 if (context_properties == null)
225 context_properties = new List<IContextProperty> ();
227 context_properties.Add (prop);
230 public virtual void Freeze ()
232 if (context_properties != null)
234 foreach (IContextProperty prop in context_properties)
239 public override string ToString()
241 return "ContextID: " + context_id;
244 internal IMessageSink GetServerContextSinkChain()
246 if (server_context_sink_chain == null)
248 if (default_server_context_sink == null)
249 default_server_context_sink = new ServerContextTerminatorSink();
251 server_context_sink_chain = default_server_context_sink;
253 if (context_properties != null) {
254 // Enumerate in reverse order
255 for (int n = context_properties.Count-1; n>=0; n--) {
256 IContributeServerContextSink contributor = context_properties[n] as IContributeServerContextSink;
257 if (contributor != null)
258 server_context_sink_chain = contributor.GetServerContextSink (server_context_sink_chain);
262 return server_context_sink_chain;
265 internal IMessageSink GetClientContextSinkChain()
267 if (client_context_sink_chain == null)
269 client_context_sink_chain = new ClientContextTerminatorSink (this);
271 if (context_properties != null) {
272 foreach (IContextProperty prop in context_properties) {
273 IContributeClientContextSink contributor = prop as IContributeClientContextSink;
274 if (contributor != null)
275 client_context_sink_chain = contributor.GetClientContextSink (client_context_sink_chain);
279 return client_context_sink_chain;
282 internal IMessageSink CreateServerObjectSinkChain (MarshalByRefObject obj, bool forceInternalExecute)
284 IMessageSink objectSink = new StackBuilderSink (obj, forceInternalExecute);
285 objectSink = new ServerObjectTerminatorSink (objectSink);
286 objectSink = new Lifetime.LeaseSink (objectSink);
288 if (context_properties != null)
290 // Contribute object sinks in reverse order
291 for (int n = context_properties.Count-1; n >= 0; n--)
293 IContextProperty prop = (IContextProperty) context_properties[n];
294 IContributeObjectSink contributor = prop as IContributeObjectSink;
295 if (contributor != null)
296 objectSink = contributor.GetObjectSink (obj, objectSink);
302 internal IMessageSink CreateEnvoySink (MarshalByRefObject serverObject)
304 IMessageSink sink = EnvoyTerminatorSink.Instance;
305 if (context_properties != null)
307 foreach (IContextProperty prop in context_properties)
309 IContributeEnvoySink contributor = prop as IContributeEnvoySink;
310 if (contributor != null)
311 sink = contributor.GetEnvoySink (serverObject, sink);
317 internal static Context SwitchToContext (Context newContext)
319 return AppDomain.InternalSetContext (newContext);
322 internal static Context CreateNewContext (IConstructionCallMessage msg)
324 // Create the new context
326 Context newContext = new Context();
328 foreach (IContextProperty prop in msg.ContextProperties)
330 if (newContext.GetProperty (prop.Name) == null)
331 newContext.SetProperty (prop);
336 // Ask each context property whether the new context is OK
338 foreach (IContextProperty prop in msg.ContextProperties)
339 if (!prop.IsNewContextOK (newContext))
340 throw new RemotingException("A context property did not approve the candidate context for activating the object");
345 public void DoCallBack (CrossContextDelegate deleg)
349 if (callback_object == null) {
350 Context oldContext = Context.SwitchToContext (this);
351 callback_object = new ContextCallbackObject ();
352 Context.SwitchToContext (oldContext);
356 callback_object.DoCallBack (deleg);
359 public static LocalDataStoreSlot AllocateDataSlot ()
361 return new LocalDataStoreSlot (false);
364 public static LocalDataStoreSlot AllocateNamedDataSlot (string name)
366 lock (NamedSlots.namedSlots.SyncRoot)
368 LocalDataStoreSlot slot = AllocateDataSlot ();
369 NamedSlots.namedSlots.Add (name, slot);
374 public static void FreeNamedDataSlot (string name)
376 lock (NamedSlots.namedSlots.SyncRoot)
378 NamedSlots.namedSlots.Remove (name);
382 public static object GetData (LocalDataStoreSlot slot)
384 Context ctx = Thread.CurrentContext;
388 if (ctx.datastore != null && slot.slot < ctx.datastore.Length)
389 return ctx.datastore [slot.slot];
394 public static LocalDataStoreSlot GetNamedDataSlot (string name)
396 lock (NamedSlots.namedSlots.SyncRoot)
398 LocalDataStoreSlot slot = NamedSlots.namedSlots [name] as LocalDataStoreSlot;
399 if (slot == null) return AllocateNamedDataSlot (name);
404 public static void SetData (LocalDataStoreSlot slot, object data)
406 Context ctx = Thread.CurrentContext;
409 if (ctx.datastore == null) {
410 ctx.datastore = new object [slot.slot + 2];
411 } else if (slot.slot >= ctx.datastore.Length) {
412 object[] nslots = new object [slot.slot + 2];
413 ctx.datastore.CopyTo (nslots, 0);
414 ctx.datastore = nslots;
416 ctx.datastore [slot.slot] = data;
421 class DynamicPropertyCollection
423 ArrayList _properties = new ArrayList();
425 class DynamicPropertyReg
427 public IDynamicProperty Property;
428 public IDynamicMessageSink Sink;
431 public bool HasProperties
433 get { return _properties.Count > 0; }
436 public bool RegisterDynamicProperty(IDynamicProperty prop)
440 if (FindProperty (prop.Name) != -1)
441 throw new InvalidOperationException ("Another property by this name already exists");
443 // Make a copy, do not interfere with threads running dynamic sinks
444 ArrayList newProps = new ArrayList (_properties);
446 DynamicPropertyReg reg = new DynamicPropertyReg();
448 IContributeDynamicSink contributor = prop as IContributeDynamicSink;
449 if (contributor != null) reg.Sink = contributor.GetDynamicSink ();
452 _properties = newProps;
454 return true; // When should be false?
458 public bool UnregisterDynamicProperty(string name)
462 int i = FindProperty (name);
463 if (i == -1) throw new RemotingException ("A property with the name " + name + " was not found");
465 _properties.RemoveAt (i);
466 return true; // When should be false?
470 public void NotifyMessage (bool start, IMessage msg, bool client_site, bool async)
472 ArrayList props = _properties;
475 foreach (DynamicPropertyReg reg in props)
476 if (reg.Sink != null) reg.Sink.ProcessMessageStart (msg, client_site, async);
480 foreach (DynamicPropertyReg reg in props)
481 if (reg.Sink != null) reg.Sink.ProcessMessageFinish (msg, client_site, async);
485 int FindProperty (string name)
487 for (int n=0; n<_properties.Count; n++)
488 if (((DynamicPropertyReg)_properties[n]).Property.Name == name)
494 class ContextCallbackObject: ContextBoundObject
496 public void DoCallBack (CrossContextDelegate deleg)