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
{
52 // Default server context sink chain
53 static IMessageSink default_server_context_sink
;
55 // The sink chain that has to be used by all calls entering the context
56 IMessageSink server_context_sink_chain
= null;
58 // The sink chain that has to be used by all calls exiting the context
59 IMessageSink client_context_sink_chain
= null;
62 ArrayList context_properties
;
65 static int global_count
;
66 static Hashtable namedSlots
;
68 static DynamicPropertyCollection global_dynamic_properties
;
69 DynamicPropertyCollection context_dynamic_properties
;
70 ContextCollbackObject callback_object
= null;
74 domain_id
= Thread
.GetDomainID();
75 context_id
= 1 + global_count
++;
82 public static Context DefaultContext
{
84 return AppDomain
.InternalGetDefaultContext ();
88 public virtual int ContextID
{
94 public IContextProperty
[] ContextProperties
98 if (context_properties
== null) return new IContextProperty
[0];
99 else return (IContextProperty
[]) context_properties
.ToArray (typeof(IContextProperty
[]));
103 internal bool IsDefaultContext
105 get { return context_id == 0; }
108 public static bool RegisterDynamicProperty(IDynamicProperty prop
, ContextBoundObject obj
, Context ctx
)
110 DynamicPropertyCollection col
= GetDynamicPropertyCollection (obj
, ctx
);
111 return col
.RegisterDynamicProperty (prop
);
114 public static bool UnregisterDynamicProperty(string name
, ContextBoundObject obj
, Context ctx
)
116 DynamicPropertyCollection col
= GetDynamicPropertyCollection (obj
, ctx
);
117 return col
.UnregisterDynamicProperty (name
);
120 static DynamicPropertyCollection
GetDynamicPropertyCollection(ContextBoundObject obj
, Context ctx
)
122 if (ctx
== null && obj
!= null)
124 if (RemotingServices
.IsTransparentProxy(obj
))
126 RealProxy rp
= RemotingServices
.GetRealProxy (obj
);
127 return rp
.ObjectIdentity
.ClientDynamicProperties
;
130 return obj
.ObjectIdentity
.ServerDynamicProperties
;
132 else if (ctx
!= null && obj
== null)
134 if (ctx
.context_dynamic_properties
== null) ctx
.context_dynamic_properties
= new DynamicPropertyCollection ();
135 return ctx
.context_dynamic_properties
;
137 else if (ctx
== null && obj
== null)
139 if (global_dynamic_properties
== null) global_dynamic_properties
= new DynamicPropertyCollection ();
140 return global_dynamic_properties
;
143 throw new ArgumentException ("Either obj or ctx must be null");
146 internal static void NotifyGlobalDynamicSinks (bool start
, IMessage req_msg
, bool client_site
, bool async)
148 if (global_dynamic_properties
!= null && global_dynamic_properties
.HasProperties
)
149 global_dynamic_properties
.NotifyMessage (start
, req_msg
, client_site
, async);
152 internal static bool HasGlobalDynamicSinks
154 get { return (global_dynamic_properties != null && global_dynamic_properties.HasProperties); }
157 internal void NotifyDynamicSinks (bool start
, IMessage req_msg
, bool client_site
, bool async)
159 if (context_dynamic_properties
!= null && context_dynamic_properties
.HasProperties
)
160 context_dynamic_properties
.NotifyMessage (start
, req_msg
, client_site
, async);
163 internal bool HasDynamicSinks
165 get { return (context_dynamic_properties != null && context_dynamic_properties.HasProperties); }
168 internal bool HasExitSinks
172 // Needs to go through the client context sink if there are custom
173 // client context or dynamic sinks.
175 return ( !(GetClientContextSinkChain() is ClientContextTerminatorSink
) || HasDynamicSinks
|| HasGlobalDynamicSinks
);
179 public virtual IContextProperty
GetProperty (string name
)
181 if (context_properties
== null)
184 foreach (IContextProperty p
in context_properties
)
191 public virtual void SetProperty (IContextProperty prop
)
194 throw new ArgumentNullException ("IContextProperty");
195 if (this == DefaultContext
)
196 throw new InvalidOperationException ("Can not add properties to " +
199 throw new InvalidOperationException ("Context is Frozen");
201 if (context_properties
== null)
202 context_properties
= new ArrayList ();
204 context_properties
.Add (prop
);
207 public virtual void Freeze ()
209 if (context_properties
!= null)
211 foreach (IContextProperty prop
in context_properties
)
216 public override string ToString()
218 return "ContextID: " + context_id
;
221 internal IMessageSink
GetServerContextSinkChain()
223 if (server_context_sink_chain
== null)
225 if (default_server_context_sink
== null)
226 default_server_context_sink
= new ServerContextTerminatorSink();
228 server_context_sink_chain
= default_server_context_sink
;
230 if (context_properties
!= null) {
231 // Enumerate in reverse order
232 for (int n
= context_properties
.Count
-1; n
>=0; n
--) {
233 IContributeServerContextSink contributor
= context_properties
[n
] as IContributeServerContextSink
;
234 if (contributor
!= null)
235 server_context_sink_chain
= contributor
.GetServerContextSink (server_context_sink_chain
);
239 return server_context_sink_chain
;
242 internal IMessageSink
GetClientContextSinkChain()
244 if (client_context_sink_chain
== null)
246 client_context_sink_chain
= new ClientContextTerminatorSink (this);
248 if (context_properties
!= null) {
249 foreach (IContextProperty prop
in context_properties
) {
250 IContributeClientContextSink contributor
= prop
as IContributeClientContextSink
;
251 if (contributor
!= null)
252 client_context_sink_chain
= contributor
.GetClientContextSink (client_context_sink_chain
);
256 return client_context_sink_chain
;
259 internal IMessageSink
CreateServerObjectSinkChain (MarshalByRefObject obj
, bool forceInternalExecute
)
261 IMessageSink objectSink
= new StackBuilderSink (obj
, forceInternalExecute
);
262 objectSink
= new ServerObjectTerminatorSink (objectSink
);
263 objectSink
= new Lifetime
.LeaseSink (objectSink
);
265 if (context_properties
!= null)
267 // Contribute object sinks in reverse order
268 for (int n
= context_properties
.Count
-1; n
>= 0; n
--)
270 IContextProperty prop
= (IContextProperty
) context_properties
[n
];
271 IContributeObjectSink contributor
= prop
as IContributeObjectSink
;
272 if (contributor
!= null)
273 objectSink
= contributor
.GetObjectSink (obj
, objectSink
);
279 internal IMessageSink
CreateEnvoySink (MarshalByRefObject serverObject
)
281 IMessageSink sink
= EnvoyTerminatorSink
.Instance
;
282 if (context_properties
!= null)
284 foreach (IContextProperty prop
in context_properties
)
286 IContributeEnvoySink contributor
= prop
as IContributeEnvoySink
;
287 if (contributor
!= null)
288 sink
= contributor
.GetEnvoySink (serverObject
, sink
);
294 internal static Context
SwitchToContext (Context newContext
)
296 return AppDomain
.InternalSetContext (newContext
);
299 internal static Context
CreateNewContext (IConstructionCallMessage msg
)
301 // Create the new context
303 Context newContext
= new Context();
305 foreach (IContextProperty prop
in msg
.ContextProperties
)
307 if (newContext
.GetProperty (prop
.Name
) == null)
308 newContext
.SetProperty (prop
);
313 // Ask each context property whether the new context is OK
315 foreach (IContextProperty prop
in msg
.ContextProperties
)
316 if (!prop
.IsNewContextOK (newContext
))
317 throw new RemotingException("A context property did not approve the candidate context for activating the object");
322 public void DoCallBack (CrossContextDelegate deleg
)
324 if (callback_object
== null)
328 if (callback_object
== null) {
329 Context oldContext
= Context
.SwitchToContext (this);
330 callback_object
= new ContextCollbackObject ();
331 Context
.SwitchToContext (oldContext
);
336 callback_object
.DoCallBack (deleg
);
339 public static LocalDataStoreSlot
AllocateDataSlot ()
341 return new LocalDataStoreSlot ();
344 public static LocalDataStoreSlot
AllocateNamedDataSlot (string name
)
346 if (namedSlots
== null)
348 lock (typeof(Context
))
350 if (namedSlots
== null)
351 namedSlots
= new Hashtable ();
355 lock (namedSlots
.SyncRoot
)
357 LocalDataStoreSlot slot
= new LocalDataStoreSlot ();
358 namedSlots
.Add (name
, slot
);
363 public static void FreeNamedDataSlot (string name
)
365 if (namedSlots
== null) return;
367 lock (namedSlots
.SyncRoot
)
369 namedSlots
.Remove (name
);
373 public static object GetData (LocalDataStoreSlot slot
)
375 Context ctx
= Thread
.CurrentContext
;
376 if (ctx
.datastore
== null) return null;
378 lock (ctx
.datastore
.SyncRoot
)
380 return ctx
.datastore
[slot
];
384 public static LocalDataStoreSlot
GetNamedDataSlot (string name
)
386 if (namedSlots
== null)
387 return AllocateNamedDataSlot (name
);
391 LocalDataStoreSlot slot
= namedSlots
[name
] as LocalDataStoreSlot
;
392 if (slot
== null) return AllocateNamedDataSlot (name
);
397 public static void SetData (LocalDataStoreSlot slot
, object data
)
399 Context ctx
= Thread
.CurrentContext
;
400 if (ctx
.datastore
== null)
404 if (ctx
.datastore
== null)
405 ctx
.datastore
= new Hashtable ();
409 lock (ctx
.datastore
.SyncRoot
)
411 ctx
.datastore
[slot
] = data
;
416 class DynamicPropertyCollection
418 ArrayList _properties
= new ArrayList();
420 class DynamicPropertyReg
422 public IDynamicProperty Property
;
423 public IDynamicMessageSink Sink
;
426 public bool HasProperties
428 get { return _properties.Count > 0; }
431 public bool RegisterDynamicProperty(IDynamicProperty prop
)
435 if (FindProperty (prop
.Name
) != -1)
436 throw new InvalidOperationException ("Another property by this name already exists");
438 // Make a copy, do not interfere with threads running dynamic sinks
439 ArrayList newProps
= new ArrayList (_properties
);
441 DynamicPropertyReg reg
= new DynamicPropertyReg();
443 IContributeDynamicSink contributor
= prop
as IContributeDynamicSink
;
444 if (contributor
!= null) reg
.Sink
= contributor
.GetDynamicSink ();
447 _properties
= newProps
;
449 return true; // When should be false?
453 public bool UnregisterDynamicProperty(string name
)
457 int i
= FindProperty (name
);
458 if (i
== -1) throw new RemotingException ("A property with the name " + name
+ " was not found");
460 _properties
.RemoveAt (i
);
461 return true; // When should be false?
465 public void NotifyMessage (bool start
, IMessage msg
, bool client_site
, bool async)
467 ArrayList props
= _properties
;
470 foreach (DynamicPropertyReg reg
in props
)
471 if (reg
.Sink
!= null) reg
.Sink
.ProcessMessageStart (msg
, client_site
, async);
475 foreach (DynamicPropertyReg reg
in props
)
476 if (reg
.Sink
!= null) reg
.Sink
.ProcessMessageFinish (msg
, client_site
, async);
480 int FindProperty (string name
)
482 for (int n
=0; n
<_properties
.Count
; n
++)
483 if (((DynamicPropertyReg
)_properties
[n
]).Property
.Name
== name
)
489 class ContextCollbackObject
: ContextBoundObject
491 public void DoCallBack (CrossContextDelegate deleg
)