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.Threading;
37 using System.Runtime.Remoting;
38 using System.Runtime.Remoting.Proxies;
39 using System.Runtime.Remoting.Activation;
40 using System.Runtime.Remoting.Messaging;
41 using System.Runtime.Remoting.Lifetime;
43 namespace System.Runtime.Remoting.Contexts {
45 [System.Runtime.InteropServices.ComVisible (true)]
48 #pragma warning disable 169, 414
49 #region Sync with domain-internals.h
52 UIntPtr static_data; /* GC-tracked */
54 #pragma warning restore 169, 414
56 // Default server context sink chain
57 static IMessageSink default_server_context_sink;
59 // The sink chain that has to be used by all calls entering the context
60 IMessageSink server_context_sink_chain = null;
62 // The sink chain that has to be used by all calls exiting the context
63 IMessageSink client_context_sink_chain = null;
66 ArrayList context_properties;
69 static int global_count;
71 /* Wrap this in a nested class so its not constructed during shutdown */
73 public static Hashtable namedSlots = new Hashtable ();
76 static DynamicPropertyCollection global_dynamic_properties;
77 DynamicPropertyCollection context_dynamic_properties;
78 ContextCallbackObject callback_object = null;
82 domain_id = Thread.GetDomainID();
83 context_id = 1 + global_count++;
90 public static Context DefaultContext {
92 return AppDomain.InternalGetDefaultContext ();
96 public virtual int ContextID {
102 public virtual IContextProperty[] ContextProperties
106 if (context_properties == null) return new IContextProperty[0];
107 else return (IContextProperty[]) context_properties.ToArray (typeof(IContextProperty[]));
111 internal bool IsDefaultContext
113 get { return context_id == 0; }
116 internal bool NeedsContextSink
119 return context_id != 0 ||
120 (global_dynamic_properties != null && global_dynamic_properties.HasProperties) ||
121 (context_dynamic_properties != null && context_dynamic_properties.HasProperties);
125 public static bool RegisterDynamicProperty(IDynamicProperty prop, ContextBoundObject obj, Context ctx)
127 DynamicPropertyCollection col = GetDynamicPropertyCollection (obj, ctx);
128 return col.RegisterDynamicProperty (prop);
131 public static bool UnregisterDynamicProperty(string name, ContextBoundObject obj, Context ctx)
133 DynamicPropertyCollection col = GetDynamicPropertyCollection (obj, ctx);
134 return col.UnregisterDynamicProperty (name);
137 static DynamicPropertyCollection GetDynamicPropertyCollection(ContextBoundObject obj, Context ctx)
139 if (ctx == null && obj != null)
141 if (RemotingServices.IsTransparentProxy(obj))
143 RealProxy rp = RemotingServices.GetRealProxy (obj);
144 return rp.ObjectIdentity.ClientDynamicProperties;
147 return obj.ObjectIdentity.ServerDynamicProperties;
149 else if (ctx != null && obj == null)
151 if (ctx.context_dynamic_properties == null) ctx.context_dynamic_properties = new DynamicPropertyCollection ();
152 return ctx.context_dynamic_properties;
154 else if (ctx == null && obj == null)
156 if (global_dynamic_properties == null) global_dynamic_properties = new DynamicPropertyCollection ();
157 return global_dynamic_properties;
160 throw new ArgumentException ("Either obj or ctx must be null");
163 internal static void NotifyGlobalDynamicSinks (bool start, IMessage req_msg, bool client_site, bool async)
165 if (global_dynamic_properties != null && global_dynamic_properties.HasProperties)
166 global_dynamic_properties.NotifyMessage (start, req_msg, client_site, async);
169 internal static bool HasGlobalDynamicSinks
171 get { return (global_dynamic_properties != null && global_dynamic_properties.HasProperties); }
174 internal void NotifyDynamicSinks (bool start, IMessage req_msg, bool client_site, bool async)
176 if (context_dynamic_properties != null && context_dynamic_properties.HasProperties)
177 context_dynamic_properties.NotifyMessage (start, req_msg, client_site, async);
180 internal bool HasDynamicSinks
182 get { return (context_dynamic_properties != null && context_dynamic_properties.HasProperties); }
185 internal bool HasExitSinks
189 // Needs to go through the client context sink if there are custom
190 // client context or dynamic sinks.
192 return ( !(GetClientContextSinkChain() is ClientContextTerminatorSink) || HasDynamicSinks || HasGlobalDynamicSinks);
196 public virtual IContextProperty GetProperty (string name)
198 if (context_properties == null)
201 foreach (IContextProperty p in context_properties)
208 public virtual void SetProperty (IContextProperty prop)
211 throw new ArgumentNullException ("IContextProperty");
212 if (this == DefaultContext)
213 throw new InvalidOperationException ("Can not add properties to " +
216 throw new InvalidOperationException ("Context is Frozen");
218 if (context_properties == null)
219 context_properties = new ArrayList ();
221 context_properties.Add (prop);
224 public virtual void Freeze ()
226 if (context_properties != null)
228 foreach (IContextProperty prop in context_properties)
233 public override string ToString()
235 return "ContextID: " + context_id;
238 internal IMessageSink GetServerContextSinkChain()
240 if (server_context_sink_chain == null)
242 if (default_server_context_sink == null)
243 default_server_context_sink = new ServerContextTerminatorSink();
245 server_context_sink_chain = default_server_context_sink;
247 if (context_properties != null) {
248 // Enumerate in reverse order
249 for (int n = context_properties.Count-1; n>=0; n--) {
250 IContributeServerContextSink contributor = context_properties[n] as IContributeServerContextSink;
251 if (contributor != null)
252 server_context_sink_chain = contributor.GetServerContextSink (server_context_sink_chain);
256 return server_context_sink_chain;
259 internal IMessageSink GetClientContextSinkChain()
261 if (client_context_sink_chain == null)
263 client_context_sink_chain = new ClientContextTerminatorSink (this);
265 if (context_properties != null) {
266 foreach (IContextProperty prop in context_properties) {
267 IContributeClientContextSink contributor = prop as IContributeClientContextSink;
268 if (contributor != null)
269 client_context_sink_chain = contributor.GetClientContextSink (client_context_sink_chain);
273 return client_context_sink_chain;
276 internal IMessageSink CreateServerObjectSinkChain (MarshalByRefObject obj, bool forceInternalExecute)
278 IMessageSink objectSink = new StackBuilderSink (obj, forceInternalExecute);
279 objectSink = new ServerObjectTerminatorSink (objectSink);
280 objectSink = new Lifetime.LeaseSink (objectSink);
282 if (context_properties != null)
284 // Contribute object sinks in reverse order
285 for (int n = context_properties.Count-1; n >= 0; n--)
287 IContextProperty prop = (IContextProperty) context_properties[n];
288 IContributeObjectSink contributor = prop as IContributeObjectSink;
289 if (contributor != null)
290 objectSink = contributor.GetObjectSink (obj, objectSink);
296 internal IMessageSink CreateEnvoySink (MarshalByRefObject serverObject)
298 IMessageSink sink = EnvoyTerminatorSink.Instance;
299 if (context_properties != null)
301 foreach (IContextProperty prop in context_properties)
303 IContributeEnvoySink contributor = prop as IContributeEnvoySink;
304 if (contributor != null)
305 sink = contributor.GetEnvoySink (serverObject, sink);
311 internal static Context SwitchToContext (Context newContext)
313 return AppDomain.InternalSetContext (newContext);
316 internal static Context CreateNewContext (IConstructionCallMessage msg)
318 // Create the new context
320 Context newContext = new Context();
322 foreach (IContextProperty prop in msg.ContextProperties)
324 if (newContext.GetProperty (prop.Name) == null)
325 newContext.SetProperty (prop);
330 // Ask each context property whether the new context is OK
332 foreach (IContextProperty prop in msg.ContextProperties)
333 if (!prop.IsNewContextOK (newContext))
334 throw new RemotingException("A context property did not approve the candidate context for activating the object");
339 public void DoCallBack (CrossContextDelegate deleg)
343 if (callback_object == null) {
344 Context oldContext = Context.SwitchToContext (this);
345 callback_object = new ContextCallbackObject ();
346 Context.SwitchToContext (oldContext);
350 callback_object.DoCallBack (deleg);
354 public static LocalDataStoreSlot AllocateDataSlot ()
356 return new LocalDataStoreSlot (false);
359 public static LocalDataStoreSlot AllocateNamedDataSlot (string name)
361 lock (NamedSlots.namedSlots.SyncRoot)
363 LocalDataStoreSlot slot = AllocateDataSlot ();
364 NamedSlots.namedSlots.Add (name, slot);
369 public static void FreeNamedDataSlot (string name)
371 lock (NamedSlots.namedSlots.SyncRoot)
373 NamedSlots.namedSlots.Remove (name);
377 public static object GetData (LocalDataStoreSlot slot)
379 Context ctx = Thread.CurrentContext;
383 if (ctx.datastore != null && slot.slot < ctx.datastore.Length)
384 return ctx.datastore [slot.slot];
389 public static LocalDataStoreSlot GetNamedDataSlot (string name)
391 lock (NamedSlots.namedSlots.SyncRoot)
393 LocalDataStoreSlot slot = NamedSlots.namedSlots [name] as LocalDataStoreSlot;
394 if (slot == null) return AllocateNamedDataSlot (name);
399 public static void SetData (LocalDataStoreSlot slot, object data)
401 Context ctx = Thread.CurrentContext;
404 if (ctx.datastore == null) {
405 ctx.datastore = new object [slot.slot + 2];
406 } else if (slot.slot >= ctx.datastore.Length) {
407 object[] nslots = new object [slot.slot + 2];
408 ctx.datastore.CopyTo (nslots, 0);
409 ctx.datastore = nslots;
411 ctx.datastore [slot.slot] = data;
417 class DynamicPropertyCollection
419 ArrayList _properties = new ArrayList();
421 class DynamicPropertyReg
423 public IDynamicProperty Property;
424 public IDynamicMessageSink Sink;
427 public bool HasProperties
429 get { return _properties.Count > 0; }
432 public bool RegisterDynamicProperty(IDynamicProperty prop)
436 if (FindProperty (prop.Name) != -1)
437 throw new InvalidOperationException ("Another property by this name already exists");
439 // Make a copy, do not interfere with threads running dynamic sinks
440 ArrayList newProps = new ArrayList (_properties);
442 DynamicPropertyReg reg = new DynamicPropertyReg();
444 IContributeDynamicSink contributor = prop as IContributeDynamicSink;
445 if (contributor != null) reg.Sink = contributor.GetDynamicSink ();
448 _properties = newProps;
450 return true; // When should be false?
454 public bool UnregisterDynamicProperty(string name)
458 int i = FindProperty (name);
459 if (i == -1) throw new RemotingException ("A property with the name " + name + " was not found");
461 _properties.RemoveAt (i);
462 return true; // When should be false?
466 public void NotifyMessage (bool start, IMessage msg, bool client_site, bool async)
468 ArrayList props = _properties;
471 foreach (DynamicPropertyReg reg in props)
472 if (reg.Sink != null) reg.Sink.ProcessMessageStart (msg, client_site, async);
476 foreach (DynamicPropertyReg reg in props)
477 if (reg.Sink != null) reg.Sink.ProcessMessageFinish (msg, client_site, async);
481 int FindProperty (string name)
483 for (int n=0; n<_properties.Count; n++)
484 if (((DynamicPropertyReg)_properties[n]).Property.Name == name)
490 class ContextCallbackObject: ContextBoundObject
492 public void DoCallBack (CrossContextDelegate deleg)