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 {
46 [System.Runtime.InteropServices.ComVisible (true)]
50 #pragma warning disable 169, 414
51 #region Sync with domain-internals.h
54 UIntPtr static_data; /* GC-tracked */
56 #pragma warning restore 169, 414
58 // Default server context sink chain
59 static IMessageSink default_server_context_sink;
61 // The sink chain that has to be used by all calls entering the context
62 IMessageSink server_context_sink_chain = null;
64 // The sink chain that has to be used by all calls exiting the context
65 IMessageSink client_context_sink_chain = null;
68 ArrayList context_properties;
71 static int global_count;
72 static Hashtable namedSlots = new Hashtable ();
74 static DynamicPropertyCollection global_dynamic_properties;
75 DynamicPropertyCollection context_dynamic_properties;
76 ContextCallbackObject callback_object = null;
80 domain_id = Thread.GetDomainID();
81 context_id = 1 + global_count++;
88 public static Context DefaultContext {
90 return AppDomain.InternalGetDefaultContext ();
94 public virtual int ContextID {
100 public virtual IContextProperty[] ContextProperties
104 if (context_properties == null) return new IContextProperty[0];
105 else return (IContextProperty[]) context_properties.ToArray (typeof(IContextProperty[]));
109 internal bool IsDefaultContext
111 get { return context_id == 0; }
114 internal bool NeedsContextSink
117 return context_id != 0 ||
118 (global_dynamic_properties != null && global_dynamic_properties.HasProperties) ||
119 (context_dynamic_properties != null && context_dynamic_properties.HasProperties);
123 public static bool RegisterDynamicProperty(IDynamicProperty prop, ContextBoundObject obj, Context ctx)
125 DynamicPropertyCollection col = GetDynamicPropertyCollection (obj, ctx);
126 return col.RegisterDynamicProperty (prop);
129 public static bool UnregisterDynamicProperty(string name, ContextBoundObject obj, Context ctx)
131 DynamicPropertyCollection col = GetDynamicPropertyCollection (obj, ctx);
132 return col.UnregisterDynamicProperty (name);
135 static DynamicPropertyCollection GetDynamicPropertyCollection(ContextBoundObject obj, Context ctx)
137 if (ctx == null && obj != null)
139 if (RemotingServices.IsTransparentProxy(obj))
141 RealProxy rp = RemotingServices.GetRealProxy (obj);
142 return rp.ObjectIdentity.ClientDynamicProperties;
145 return obj.ObjectIdentity.ServerDynamicProperties;
147 else if (ctx != null && obj == null)
149 if (ctx.context_dynamic_properties == null) ctx.context_dynamic_properties = new DynamicPropertyCollection ();
150 return ctx.context_dynamic_properties;
152 else if (ctx == null && obj == null)
154 if (global_dynamic_properties == null) global_dynamic_properties = new DynamicPropertyCollection ();
155 return global_dynamic_properties;
158 throw new ArgumentException ("Either obj or ctx must be null");
161 internal static void NotifyGlobalDynamicSinks (bool start, IMessage req_msg, bool client_site, bool async)
163 if (global_dynamic_properties != null && global_dynamic_properties.HasProperties)
164 global_dynamic_properties.NotifyMessage (start, req_msg, client_site, async);
167 internal static bool HasGlobalDynamicSinks
169 get { return (global_dynamic_properties != null && global_dynamic_properties.HasProperties); }
172 internal void NotifyDynamicSinks (bool start, IMessage req_msg, bool client_site, bool async)
174 if (context_dynamic_properties != null && context_dynamic_properties.HasProperties)
175 context_dynamic_properties.NotifyMessage (start, req_msg, client_site, async);
178 internal bool HasDynamicSinks
180 get { return (context_dynamic_properties != null && context_dynamic_properties.HasProperties); }
183 internal bool HasExitSinks
187 // Needs to go through the client context sink if there are custom
188 // client context or dynamic sinks.
190 return ( !(GetClientContextSinkChain() is ClientContextTerminatorSink) || HasDynamicSinks || HasGlobalDynamicSinks);
194 public virtual IContextProperty GetProperty (string name)
196 if (context_properties == null)
199 foreach (IContextProperty p in context_properties)
206 public virtual void SetProperty (IContextProperty prop)
209 throw new ArgumentNullException ("IContextProperty");
210 if (this == DefaultContext)
211 throw new InvalidOperationException ("Can not add properties to " +
214 throw new InvalidOperationException ("Context is Frozen");
216 if (context_properties == null)
217 context_properties = new ArrayList ();
219 context_properties.Add (prop);
222 public virtual void Freeze ()
224 if (context_properties != null)
226 foreach (IContextProperty prop in context_properties)
231 public override string ToString()
233 return "ContextID: " + context_id;
236 internal IMessageSink GetServerContextSinkChain()
238 if (server_context_sink_chain == null)
240 if (default_server_context_sink == null)
241 default_server_context_sink = new ServerContextTerminatorSink();
243 server_context_sink_chain = default_server_context_sink;
245 if (context_properties != null) {
246 // Enumerate in reverse order
247 for (int n = context_properties.Count-1; n>=0; n--) {
248 IContributeServerContextSink contributor = context_properties[n] as IContributeServerContextSink;
249 if (contributor != null)
250 server_context_sink_chain = contributor.GetServerContextSink (server_context_sink_chain);
254 return server_context_sink_chain;
257 internal IMessageSink GetClientContextSinkChain()
259 if (client_context_sink_chain == null)
261 client_context_sink_chain = new ClientContextTerminatorSink (this);
263 if (context_properties != null) {
264 foreach (IContextProperty prop in context_properties) {
265 IContributeClientContextSink contributor = prop as IContributeClientContextSink;
266 if (contributor != null)
267 client_context_sink_chain = contributor.GetClientContextSink (client_context_sink_chain);
271 return client_context_sink_chain;
274 internal IMessageSink CreateServerObjectSinkChain (MarshalByRefObject obj, bool forceInternalExecute)
276 IMessageSink objectSink = new StackBuilderSink (obj, forceInternalExecute);
277 objectSink = new ServerObjectTerminatorSink (objectSink);
278 objectSink = new Lifetime.LeaseSink (objectSink);
280 if (context_properties != null)
282 // Contribute object sinks in reverse order
283 for (int n = context_properties.Count-1; n >= 0; n--)
285 IContextProperty prop = (IContextProperty) context_properties[n];
286 IContributeObjectSink contributor = prop as IContributeObjectSink;
287 if (contributor != null)
288 objectSink = contributor.GetObjectSink (obj, objectSink);
294 internal IMessageSink CreateEnvoySink (MarshalByRefObject serverObject)
296 IMessageSink sink = EnvoyTerminatorSink.Instance;
297 if (context_properties != null)
299 foreach (IContextProperty prop in context_properties)
301 IContributeEnvoySink contributor = prop as IContributeEnvoySink;
302 if (contributor != null)
303 sink = contributor.GetEnvoySink (serverObject, sink);
309 internal static Context SwitchToContext (Context newContext)
311 return AppDomain.InternalSetContext (newContext);
314 internal static Context CreateNewContext (IConstructionCallMessage msg)
316 // Create the new context
318 Context newContext = new Context();
320 foreach (IContextProperty prop in msg.ContextProperties)
322 if (newContext.GetProperty (prop.Name) == null)
323 newContext.SetProperty (prop);
328 // Ask each context property whether the new context is OK
330 foreach (IContextProperty prop in msg.ContextProperties)
331 if (!prop.IsNewContextOK (newContext))
332 throw new RemotingException("A context property did not approve the candidate context for activating the object");
337 public void DoCallBack (CrossContextDelegate deleg)
341 if (callback_object == null) {
342 Context oldContext = Context.SwitchToContext (this);
343 callback_object = new ContextCallbackObject ();
344 Context.SwitchToContext (oldContext);
348 callback_object.DoCallBack (deleg);
351 public static LocalDataStoreSlot AllocateDataSlot ()
353 return new LocalDataStoreSlot (false);
356 public static LocalDataStoreSlot AllocateNamedDataSlot (string name)
358 lock (namedSlots.SyncRoot)
360 LocalDataStoreSlot slot = AllocateDataSlot ();
361 namedSlots.Add (name, slot);
366 public static void FreeNamedDataSlot (string name)
368 lock (namedSlots.SyncRoot)
370 namedSlots.Remove (name);
374 public static object GetData (LocalDataStoreSlot slot)
376 Context ctx = Thread.CurrentContext;
380 if (ctx.datastore != null && slot.slot < ctx.datastore.Length)
381 return ctx.datastore [slot.slot];
386 public static LocalDataStoreSlot GetNamedDataSlot (string name)
388 lock (namedSlots.SyncRoot)
390 LocalDataStoreSlot slot = namedSlots [name] as LocalDataStoreSlot;
391 if (slot == null) return AllocateNamedDataSlot (name);
396 public static void SetData (LocalDataStoreSlot slot, object data)
398 Context ctx = Thread.CurrentContext;
401 if (ctx.datastore == null) {
402 ctx.datastore = new object [slot.slot + 2];
403 } else if (slot.slot >= ctx.datastore.Length) {
404 object[] nslots = new object [slot.slot + 2];
405 ctx.datastore.CopyTo (nslots, 0);
406 ctx.datastore = nslots;
408 ctx.datastore [slot.slot] = data;
413 class DynamicPropertyCollection
415 ArrayList _properties = new ArrayList();
417 class DynamicPropertyReg
419 public IDynamicProperty Property;
420 public IDynamicMessageSink Sink;
423 public bool HasProperties
425 get { return _properties.Count > 0; }
428 public bool RegisterDynamicProperty(IDynamicProperty prop)
432 if (FindProperty (prop.Name) != -1)
433 throw new InvalidOperationException ("Another property by this name already exists");
435 // Make a copy, do not interfere with threads running dynamic sinks
436 ArrayList newProps = new ArrayList (_properties);
438 DynamicPropertyReg reg = new DynamicPropertyReg();
440 IContributeDynamicSink contributor = prop as IContributeDynamicSink;
441 if (contributor != null) reg.Sink = contributor.GetDynamicSink ();
444 _properties = newProps;
446 return true; // When should be false?
450 public bool UnregisterDynamicProperty(string name)
454 int i = FindProperty (name);
455 if (i == -1) throw new RemotingException ("A property with the name " + name + " was not found");
457 _properties.RemoveAt (i);
458 return true; // When should be false?
462 public void NotifyMessage (bool start, IMessage msg, bool client_site, bool async)
464 ArrayList props = _properties;
467 foreach (DynamicPropertyReg reg in props)
468 if (reg.Sink != null) reg.Sink.ProcessMessageStart (msg, client_site, async);
472 foreach (DynamicPropertyReg reg in props)
473 if (reg.Sink != null) reg.Sink.ProcessMessageFinish (msg, client_site, async);
477 int FindProperty (string name)
479 for (int n=0; n<_properties.Count; n++)
480 if (((DynamicPropertyReg)_properties[n]).Property.Name == name)
486 class ContextCallbackObject: ContextBoundObject
488 public void DoCallBack (CrossContextDelegate deleg)