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;
70 static Hashtable namedSlots = new Hashtable ();
72 static DynamicPropertyCollection global_dynamic_properties;
73 DynamicPropertyCollection context_dynamic_properties;
74 ContextCallbackObject callback_object = null;
78 domain_id = Thread.GetDomainID();
79 context_id = 1 + global_count++;
86 public static Context DefaultContext {
88 return AppDomain.InternalGetDefaultContext ();
92 public virtual int ContextID {
98 public virtual IContextProperty[] ContextProperties
102 if (context_properties == null) return new IContextProperty[0];
103 else return (IContextProperty[]) context_properties.ToArray (typeof(IContextProperty[]));
107 internal bool IsDefaultContext
109 get { return context_id == 0; }
112 internal bool NeedsContextSink
115 return context_id != 0 ||
116 (global_dynamic_properties != null && global_dynamic_properties.HasProperties) ||
117 (context_dynamic_properties != null && context_dynamic_properties.HasProperties);
121 public static bool RegisterDynamicProperty(IDynamicProperty prop, ContextBoundObject obj, Context ctx)
123 DynamicPropertyCollection col = GetDynamicPropertyCollection (obj, ctx);
124 return col.RegisterDynamicProperty (prop);
127 public static bool UnregisterDynamicProperty(string name, ContextBoundObject obj, Context ctx)
129 DynamicPropertyCollection col = GetDynamicPropertyCollection (obj, ctx);
130 return col.UnregisterDynamicProperty (name);
133 static DynamicPropertyCollection GetDynamicPropertyCollection(ContextBoundObject obj, Context ctx)
135 if (ctx == null && obj != null)
137 if (RemotingServices.IsTransparentProxy(obj))
139 RealProxy rp = RemotingServices.GetRealProxy (obj);
140 return rp.ObjectIdentity.ClientDynamicProperties;
143 return obj.ObjectIdentity.ServerDynamicProperties;
145 else if (ctx != null && obj == null)
147 if (ctx.context_dynamic_properties == null) ctx.context_dynamic_properties = new DynamicPropertyCollection ();
148 return ctx.context_dynamic_properties;
150 else if (ctx == null && obj == null)
152 if (global_dynamic_properties == null) global_dynamic_properties = new DynamicPropertyCollection ();
153 return global_dynamic_properties;
156 throw new ArgumentException ("Either obj or ctx must be null");
159 internal static void NotifyGlobalDynamicSinks (bool start, IMessage req_msg, bool client_site, bool async)
161 if (global_dynamic_properties != null && global_dynamic_properties.HasProperties)
162 global_dynamic_properties.NotifyMessage (start, req_msg, client_site, async);
165 internal static bool HasGlobalDynamicSinks
167 get { return (global_dynamic_properties != null && global_dynamic_properties.HasProperties); }
170 internal void NotifyDynamicSinks (bool start, IMessage req_msg, bool client_site, bool async)
172 if (context_dynamic_properties != null && context_dynamic_properties.HasProperties)
173 context_dynamic_properties.NotifyMessage (start, req_msg, client_site, async);
176 internal bool HasDynamicSinks
178 get { return (context_dynamic_properties != null && context_dynamic_properties.HasProperties); }
181 internal bool HasExitSinks
185 // Needs to go through the client context sink if there are custom
186 // client context or dynamic sinks.
188 return ( !(GetClientContextSinkChain() is ClientContextTerminatorSink) || HasDynamicSinks || HasGlobalDynamicSinks);
192 public virtual IContextProperty GetProperty (string name)
194 if (context_properties == null)
197 foreach (IContextProperty p in context_properties)
204 public virtual void SetProperty (IContextProperty prop)
207 throw new ArgumentNullException ("IContextProperty");
208 if (this == DefaultContext)
209 throw new InvalidOperationException ("Can not add properties to " +
212 throw new InvalidOperationException ("Context is Frozen");
214 if (context_properties == null)
215 context_properties = new ArrayList ();
217 context_properties.Add (prop);
220 public virtual void Freeze ()
222 if (context_properties != null)
224 foreach (IContextProperty prop in context_properties)
229 public override string ToString()
231 return "ContextID: " + context_id;
234 internal IMessageSink GetServerContextSinkChain()
236 if (server_context_sink_chain == null)
238 if (default_server_context_sink == null)
239 default_server_context_sink = new ServerContextTerminatorSink();
241 server_context_sink_chain = default_server_context_sink;
243 if (context_properties != null) {
244 // Enumerate in reverse order
245 for (int n = context_properties.Count-1; n>=0; n--) {
246 IContributeServerContextSink contributor = context_properties[n] as IContributeServerContextSink;
247 if (contributor != null)
248 server_context_sink_chain = contributor.GetServerContextSink (server_context_sink_chain);
252 return server_context_sink_chain;
255 internal IMessageSink GetClientContextSinkChain()
257 if (client_context_sink_chain == null)
259 client_context_sink_chain = new ClientContextTerminatorSink (this);
261 if (context_properties != null) {
262 foreach (IContextProperty prop in context_properties) {
263 IContributeClientContextSink contributor = prop as IContributeClientContextSink;
264 if (contributor != null)
265 client_context_sink_chain = contributor.GetClientContextSink (client_context_sink_chain);
269 return client_context_sink_chain;
272 internal IMessageSink CreateServerObjectSinkChain (MarshalByRefObject obj, bool forceInternalExecute)
274 IMessageSink objectSink = new StackBuilderSink (obj, forceInternalExecute);
275 objectSink = new ServerObjectTerminatorSink (objectSink);
276 objectSink = new Lifetime.LeaseSink (objectSink);
278 if (context_properties != null)
280 // Contribute object sinks in reverse order
281 for (int n = context_properties.Count-1; n >= 0; n--)
283 IContextProperty prop = (IContextProperty) context_properties[n];
284 IContributeObjectSink contributor = prop as IContributeObjectSink;
285 if (contributor != null)
286 objectSink = contributor.GetObjectSink (obj, objectSink);
292 internal IMessageSink CreateEnvoySink (MarshalByRefObject serverObject)
294 IMessageSink sink = EnvoyTerminatorSink.Instance;
295 if (context_properties != null)
297 foreach (IContextProperty prop in context_properties)
299 IContributeEnvoySink contributor = prop as IContributeEnvoySink;
300 if (contributor != null)
301 sink = contributor.GetEnvoySink (serverObject, sink);
307 internal static Context SwitchToContext (Context newContext)
309 return AppDomain.InternalSetContext (newContext);
312 internal static Context CreateNewContext (IConstructionCallMessage msg)
314 // Create the new context
316 Context newContext = new Context();
318 foreach (IContextProperty prop in msg.ContextProperties)
320 if (newContext.GetProperty (prop.Name) == null)
321 newContext.SetProperty (prop);
326 // Ask each context property whether the new context is OK
328 foreach (IContextProperty prop in msg.ContextProperties)
329 if (!prop.IsNewContextOK (newContext))
330 throw new RemotingException("A context property did not approve the candidate context for activating the object");
335 public void DoCallBack (CrossContextDelegate deleg)
339 if (callback_object == null) {
340 Context oldContext = Context.SwitchToContext (this);
341 callback_object = new ContextCallbackObject ();
342 Context.SwitchToContext (oldContext);
346 callback_object.DoCallBack (deleg);
350 public static LocalDataStoreSlot AllocateDataSlot ()
352 return new LocalDataStoreSlot (false);
355 public static LocalDataStoreSlot AllocateNamedDataSlot (string name)
357 lock (namedSlots.SyncRoot)
359 LocalDataStoreSlot slot = AllocateDataSlot ();
360 namedSlots.Add (name, slot);
365 public static void FreeNamedDataSlot (string name)
367 lock (namedSlots.SyncRoot)
369 namedSlots.Remove (name);
373 public static object GetData (LocalDataStoreSlot slot)
375 Context ctx = Thread.CurrentContext;
379 if (ctx.datastore != null && slot.slot < ctx.datastore.Length)
380 return ctx.datastore [slot.slot];
385 public static LocalDataStoreSlot GetNamedDataSlot (string name)
387 lock (namedSlots.SyncRoot)
389 LocalDataStoreSlot slot = namedSlots [name] as LocalDataStoreSlot;
390 if (slot == null) return AllocateNamedDataSlot (name);
395 public static void SetData (LocalDataStoreSlot slot, object data)
397 Context ctx = Thread.CurrentContext;
400 if (ctx.datastore == null) {
401 ctx.datastore = new object [slot.slot + 2];
402 } else if (slot.slot >= ctx.datastore.Length) {
403 object[] nslots = new object [slot.slot + 2];
404 ctx.datastore.CopyTo (nslots, 0);
405 ctx.datastore = nslots;
407 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)