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;
155 return obj.ObjectIdentity.ServerDynamicProperties;
157 throw new NotSupportedException ();
161 else if (ctx != null && obj == null)
163 if (ctx.context_dynamic_properties == null) ctx.context_dynamic_properties = new DynamicPropertyCollection ();
164 return ctx.context_dynamic_properties;
166 else if (ctx == null && obj == null)
168 if (global_dynamic_properties == null) global_dynamic_properties = new DynamicPropertyCollection ();
169 return global_dynamic_properties;
172 throw new ArgumentException ("Either obj or ctx must be null");
175 internal static void NotifyGlobalDynamicSinks (bool start, IMessage req_msg, bool client_site, bool async)
177 if (global_dynamic_properties != null && global_dynamic_properties.HasProperties)
178 global_dynamic_properties.NotifyMessage (start, req_msg, client_site, async);
181 internal static bool HasGlobalDynamicSinks
183 get { return (global_dynamic_properties != null && global_dynamic_properties.HasProperties); }
186 internal void NotifyDynamicSinks (bool start, IMessage req_msg, bool client_site, bool async)
188 if (context_dynamic_properties != null && context_dynamic_properties.HasProperties)
189 context_dynamic_properties.NotifyMessage (start, req_msg, client_site, async);
192 internal bool HasDynamicSinks
194 get { return (context_dynamic_properties != null && context_dynamic_properties.HasProperties); }
197 internal bool HasExitSinks
201 // Needs to go through the client context sink if there are custom
202 // client context or dynamic sinks.
204 return ( !(GetClientContextSinkChain() is ClientContextTerminatorSink) || HasDynamicSinks || HasGlobalDynamicSinks);
208 public virtual IContextProperty GetProperty (string name)
210 if (context_properties == null)
213 foreach (IContextProperty p in context_properties)
220 public virtual void SetProperty (IContextProperty prop)
223 throw new ArgumentNullException ("IContextProperty");
224 if (this == DefaultContext)
225 throw new InvalidOperationException ("Can not add properties to " +
228 // throw new InvalidOperationException ("Context is Frozen");
230 if (context_properties == null)
231 context_properties = new List<IContextProperty> ();
233 context_properties.Add (prop);
236 public virtual void Freeze ()
238 if (context_properties != null)
240 foreach (IContextProperty prop in context_properties)
245 public override string ToString()
247 return "ContextID: " + context_id;
250 internal IMessageSink GetServerContextSinkChain()
252 if (server_context_sink_chain == null)
254 if (default_server_context_sink == null)
255 default_server_context_sink = new ServerContextTerminatorSink();
257 server_context_sink_chain = default_server_context_sink;
259 if (context_properties != null) {
260 // Enumerate in reverse order
261 for (int n = context_properties.Count-1; n>=0; n--) {
262 IContributeServerContextSink contributor = context_properties[n] as IContributeServerContextSink;
263 if (contributor != null)
264 server_context_sink_chain = contributor.GetServerContextSink (server_context_sink_chain);
268 return server_context_sink_chain;
271 internal IMessageSink GetClientContextSinkChain()
273 if (client_context_sink_chain == null)
275 client_context_sink_chain = new ClientContextTerminatorSink (this);
277 if (context_properties != null) {
278 foreach (IContextProperty prop in context_properties) {
279 IContributeClientContextSink contributor = prop as IContributeClientContextSink;
280 if (contributor != null)
281 client_context_sink_chain = contributor.GetClientContextSink (client_context_sink_chain);
285 return client_context_sink_chain;
288 internal IMessageSink CreateServerObjectSinkChain (MarshalByRefObject obj, bool forceInternalExecute)
290 IMessageSink objectSink = new StackBuilderSink (obj, forceInternalExecute);
291 objectSink = new ServerObjectTerminatorSink (objectSink);
292 objectSink = new Lifetime.LeaseSink (objectSink);
294 if (context_properties != null)
296 // Contribute object sinks in reverse order
297 for (int n = context_properties.Count-1; n >= 0; n--)
299 IContextProperty prop = (IContextProperty) context_properties[n];
300 IContributeObjectSink contributor = prop as IContributeObjectSink;
301 if (contributor != null)
302 objectSink = contributor.GetObjectSink (obj, objectSink);
308 internal IMessageSink CreateEnvoySink (MarshalByRefObject serverObject)
310 IMessageSink sink = EnvoyTerminatorSink.Instance;
311 if (context_properties != null)
313 foreach (IContextProperty prop in context_properties)
315 IContributeEnvoySink contributor = prop as IContributeEnvoySink;
316 if (contributor != null)
317 sink = contributor.GetEnvoySink (serverObject, sink);
323 internal static Context SwitchToContext (Context newContext)
325 return AppDomain.InternalSetContext (newContext);
328 internal static Context CreateNewContext (IConstructionCallMessage msg)
330 // Create the new context
332 Context newContext = new Context();
334 foreach (IContextProperty prop in msg.ContextProperties)
336 if (newContext.GetProperty (prop.Name) == null)
337 newContext.SetProperty (prop);
342 // Ask each context property whether the new context is OK
344 foreach (IContextProperty prop in msg.ContextProperties)
345 if (!prop.IsNewContextOK (newContext))
346 throw new RemotingException("A context property did not approve the candidate context for activating the object");
351 public void DoCallBack (CrossContextDelegate deleg)
355 if (callback_object == null) {
356 Context oldContext = Context.SwitchToContext (this);
357 callback_object = new ContextCallbackObject ();
358 Context.SwitchToContext (oldContext);
362 callback_object.DoCallBack (deleg);
365 public static LocalDataStoreSlot AllocateDataSlot ()
367 return new LocalDataStoreSlot (false);
370 public static LocalDataStoreSlot AllocateNamedDataSlot (string name)
372 lock (NamedSlots.namedSlots.SyncRoot)
374 LocalDataStoreSlot slot = AllocateDataSlot ();
375 NamedSlots.namedSlots.Add (name, slot);
380 public static void FreeNamedDataSlot (string name)
382 lock (NamedSlots.namedSlots.SyncRoot)
384 NamedSlots.namedSlots.Remove (name);
388 public static object GetData (LocalDataStoreSlot slot)
390 Context ctx = Thread.CurrentContext;
394 if (ctx.datastore != null && slot.slot < ctx.datastore.Length)
395 return ctx.datastore [slot.slot];
400 public static LocalDataStoreSlot GetNamedDataSlot (string name)
402 lock (NamedSlots.namedSlots.SyncRoot)
404 LocalDataStoreSlot slot = NamedSlots.namedSlots [name] as LocalDataStoreSlot;
405 if (slot == null) return AllocateNamedDataSlot (name);
410 public static void SetData (LocalDataStoreSlot slot, object data)
412 Context ctx = Thread.CurrentContext;
415 if (ctx.datastore == null) {
416 ctx.datastore = new object [slot.slot + 2];
417 } else if (slot.slot >= ctx.datastore.Length) {
418 object[] nslots = new object [slot.slot + 2];
419 ctx.datastore.CopyTo (nslots, 0);
420 ctx.datastore = nslots;
422 ctx.datastore [slot.slot] = data;
427 class DynamicPropertyCollection
429 ArrayList _properties = new ArrayList();
431 class DynamicPropertyReg
433 public IDynamicProperty Property;
434 public IDynamicMessageSink Sink;
437 public bool HasProperties
439 get { return _properties.Count > 0; }
442 public bool RegisterDynamicProperty(IDynamicProperty prop)
446 if (FindProperty (prop.Name) != -1)
447 throw new InvalidOperationException ("Another property by this name already exists");
449 // Make a copy, do not interfere with threads running dynamic sinks
450 ArrayList newProps = new ArrayList (_properties);
452 DynamicPropertyReg reg = new DynamicPropertyReg();
454 IContributeDynamicSink contributor = prop as IContributeDynamicSink;
455 if (contributor != null) reg.Sink = contributor.GetDynamicSink ();
458 _properties = newProps;
460 return true; // When should be false?
464 public bool UnregisterDynamicProperty(string name)
468 int i = FindProperty (name);
469 if (i == -1) throw new RemotingException ("A property with the name " + name + " was not found");
471 _properties.RemoveAt (i);
472 return true; // When should be false?
476 public void NotifyMessage (bool start, IMessage msg, bool client_site, bool async)
478 ArrayList props = _properties;
481 foreach (DynamicPropertyReg reg in props)
482 if (reg.Sink != null) reg.Sink.ProcessMessageStart (msg, client_site, async);
486 foreach (DynamicPropertyReg reg in props)
487 if (reg.Sink != null) reg.Sink.ProcessMessageFinish (msg, client_site, async);
491 int FindProperty (string name)
493 for (int n=0; n<_properties.Count; n++)
494 if (((DynamicPropertyReg)_properties[n]).Property.Name == name)
500 class ContextCallbackObject: ContextBoundObject
502 public void DoCallBack (CrossContextDelegate deleg)