This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[mono.git] / mcs / class / corlib / System.Runtime.Remoting / RemotingServices.cs
1 //
2 // System.Runtime.Remoting.RemotingServices.cs
3 //
4 // Authors:
5 //   Dietmar Maurer (dietmar@ximian.com)
6 //   Lluis Sanchez Gual (lluis@ideary.com)
7 //   Patrik Torstensson
8 //
9 // (C) 2001 Ximian, Inc.  http://www.ximian.com
10 //
11
12 //
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 //
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:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
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.
33 //
34
35 using System;
36 using System.Diagnostics;
37 using System.Text;
38 using System.Reflection;
39 using System.Threading;
40 using System.Collections;
41 using System.Runtime.Remoting.Messaging;
42 using System.Runtime.Remoting.Proxies;
43 using System.Runtime.Remoting.Channels;
44 using System.Runtime.Remoting.Contexts;
45 using System.Runtime.Remoting.Activation;
46 using System.Runtime.Remoting.Lifetime;
47 using System.Runtime.CompilerServices;
48 using System.Runtime.Serialization;
49 using System.IO;
50
51 namespace System.Runtime.Remoting
52 {
53         public sealed class RemotingServices 
54         {
55                 // Holds the identities of the objects, using uri as index
56                 static Hashtable uri_hash = new Hashtable ();           
57
58                 internal static string app_id;
59                 static int next_id = 1;
60                 static readonly BindingFlags methodBindings = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
61                 
62                 static RemotingServices ()
63                 {
64                         RegisterInternalChannels ();
65                         app_id = Guid.NewGuid().ToString().Replace('-', '_') + "/";
66                         CreateWellKnownServerIdentity (typeof(RemoteActivator), "RemoteActivationService.rem", WellKnownObjectMode.Singleton);
67                 }
68         
69                 private RemotingServices () {}
70
71                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
72                 internal extern static object InternalExecute (MonoMethod method, Object obj,
73                                                                Object[] parameters, out object [] out_args);
74
75                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
76                 public extern static bool IsTransparentProxy (object proxy);
77                 
78                 internal static IMethodReturnMessage InternalExecuteMessage (
79                         MarshalByRefObject target, IMethodCallMessage reqMsg)
80                 {
81                         ReturnMessage result;
82                         
83                         MonoMethod method = (MonoMethod) target.GetType().GetMethod(reqMsg.MethodName, BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance, null, (Type[]) reqMsg.MethodSignature, null);
84                         object oldContext = CallContext.SetCurrentCallContext (reqMsg.LogicalCallContext);
85                         
86                         try 
87                         {
88                                 object [] out_args;
89                                 object rval = InternalExecute (method, target, reqMsg.Args, out out_args);
90                         
91                                 // Collect parameters with Out flag from the request message
92                                 // FIXME: This can be done in the unmanaged side and will be
93                                 // more efficient
94                                 
95                                 ParameterInfo[] parameters = method.GetParameters();
96                                 object[] returnArgs = new object [parameters.Length];
97                                 
98                                 int n = 0;
99                                 int noa = 0;
100                                 foreach (ParameterInfo par in parameters)
101                                 {
102                                         if (par.IsOut && !par.ParameterType.IsByRef) 
103                                                 returnArgs [n++] = reqMsg.GetArg (par.Position);
104                                         else if (par.ParameterType.IsByRef)
105                                                 returnArgs [n++] = out_args [noa++]; 
106                                         else
107                                                 returnArgs [n++] = null; 
108                                 }
109                                 
110                                 result = new ReturnMessage (rval, returnArgs, n, CallContext.CreateLogicalCallContext(), reqMsg);
111                         } 
112                         catch (Exception e) 
113                         {
114                                 result = new ReturnMessage (e, reqMsg);
115                         }
116                         
117                         CallContext.RestoreCallContext (oldContext);
118                         return result;
119                 }
120
121                 public static IMethodReturnMessage ExecuteMessage (
122                         MarshalByRefObject target, IMethodCallMessage reqMsg)
123                 {
124                         if (IsTransparentProxy(target))
125                         {
126                                 // Message must go through all chain of sinks
127                                 RealProxy rp = GetRealProxy (target);
128                                 return (IMethodReturnMessage) rp.Invoke (reqMsg);
129                         }
130                         else    // Direct call
131                                 return InternalExecuteMessage (target, reqMsg);
132                 }
133
134                 public static object Connect (Type classToProxy, string url)
135                 {
136                         ObjRef objRef = new ObjRef (classToProxy, url, null);
137                         return GetRemoteObject (objRef, classToProxy);
138                 }
139
140                 public static object Connect (Type classToProxy, string url, object data)
141                 {
142                         ObjRef objRef = new ObjRef (classToProxy, url, data);
143                         return GetRemoteObject (objRef, classToProxy);
144                 }
145
146                 public static bool Disconnect (MarshalByRefObject obj)
147                 {
148                         if (obj == null) throw new ArgumentNullException ("obj");
149
150                         ServerIdentity identity;
151
152                         if (IsTransparentProxy (obj))
153                         {
154                                 // CBOs are always accessed through a proxy, even in the server, so
155                                 // for server CBOs it is ok to disconnect a proxy
156
157                                 RealProxy proxy = GetRealProxy(obj);
158                                 if (proxy.GetProxiedType().IsContextful && (proxy.ObjectIdentity is ServerIdentity))
159                                         identity = proxy.ObjectIdentity as ServerIdentity;
160                                 else
161                                         throw new ArgumentException ("The obj parameter is a proxy.");
162                         }
163                         else {
164                                 identity = obj.ObjectIdentity;
165                                 obj.ObjectIdentity = null;
166                         }
167
168                         if (identity == null || !identity.IsConnected)
169                                 return false;
170                         else
171                         {
172                                 LifetimeServices.StopTrackingLifetime (identity);
173                                 DisposeIdentity (identity);
174                                 return true;
175                         }
176                 }
177
178                 public static Type GetServerTypeForUri (string uri)
179                 {
180                         ServerIdentity ident = GetIdentityForUri (uri) as ServerIdentity;
181                         if (ident == null) return null;
182                         return ident.ObjectType;
183                 }
184
185                 public static string GetObjectUri (MarshalByRefObject obj)
186                 {
187                         Identity ident = GetObjectIdentity(obj);
188                         if (ident is ClientIdentity) return ((ClientIdentity)ident).TargetUri;
189                         else if (ident != null) return ident.ObjectUri;
190                         else return null;
191                 }
192
193                 public static object Unmarshal (ObjRef objref)
194                 {
195                         return Unmarshal(objref, true);
196                 }
197
198                 public static object Unmarshal (ObjRef objref, bool fRefine)
199                 {
200                         Type classToProxy = fRefine ? objref.ServerType : typeof (MarshalByRefObject);
201                         if (classToProxy == null) classToProxy = typeof (MarshalByRefObject);
202
203                         if (objref.IsReferenceToWellKnow)
204                                 return GetRemoteObject(objref, classToProxy);
205                         else
206                         {
207                                 if (classToProxy.IsContextful)
208                                 {
209                                         // Look for a ProxyAttribute
210                                         ProxyAttribute att = (ProxyAttribute) Attribute.GetCustomAttribute (classToProxy, typeof(ProxyAttribute),true);
211                                         if (att != null)
212                                                 return att.CreateProxy (objref, classToProxy, null, null).GetTransparentProxy();
213                                 }
214                                 return GetProxyForRemoteObject (objref, classToProxy);
215                         }
216                 }
217
218                 public static ObjRef Marshal (MarshalByRefObject obj)
219                 {
220                         return Marshal (obj, null, null);
221                 }
222                 
223                 public static ObjRef Marshal (MarshalByRefObject obj, string uri)
224                 {
225                         return Marshal (obj, uri, null);
226                 }
227                 
228                 public static ObjRef Marshal (MarshalByRefObject obj, string uri, Type requested_type)
229                 {
230                         if (IsTransparentProxy (obj))
231                         {
232                                 RealProxy proxy = RemotingServices.GetRealProxy(obj);
233                                 Identity identity = proxy.ObjectIdentity;
234
235                                 if (identity != null)
236                                 {
237                                         if (proxy.GetProxiedType().IsContextful && !identity.IsConnected)
238                                         {
239                                                 // Unregistered local contextbound object. Register now.
240                                                 ClientActivatedIdentity cboundIdentity = (ClientActivatedIdentity)identity;
241                                                 if (uri == null) uri = NewUri();
242                                                 cboundIdentity.ObjectUri = uri;
243                                                 RegisterServerIdentity (cboundIdentity);
244                                                 cboundIdentity.StartTrackingLifetime ((ILease)obj.InitializeLifetimeService());
245                                                 return cboundIdentity.CreateObjRef(requested_type);
246                                         }
247                                         else if (uri != null)
248                                                 throw new RemotingException ("It is not possible marshal a proxy of a remote object.");
249
250                                         return proxy.ObjectIdentity.CreateObjRef(requested_type);
251                                 }
252                         }
253
254                         if (requested_type == null) requested_type = obj.GetType();
255
256                         if (uri == null) 
257                         {
258                                 if (obj.ObjectIdentity == null)
259                                 {
260                                         uri = NewUri();
261                                         CreateClientActivatedServerIdentity (obj, requested_type, uri);
262                                 }
263                         }
264                         else
265                         {
266                                 ClientActivatedIdentity identity = GetIdentityForUri ("/" + uri) as ClientActivatedIdentity;
267                                 if (identity == null || obj != identity.GetServerObject()) 
268                                         CreateClientActivatedServerIdentity (obj, requested_type, uri);
269                         }
270
271                         if (IsTransparentProxy (obj))
272                                 return RemotingServices.GetRealProxy(obj).ObjectIdentity.CreateObjRef (requested_type);
273                         else
274                                 return obj.CreateObjRef(requested_type);
275                 }
276
277                 static string NewUri ()
278                 {
279                         int n = Interlocked.Increment (ref next_id);
280                         return app_id + Environment.TickCount + "_" + n + ".rem";
281                 }
282
283                 public static RealProxy GetRealProxy (object proxy)
284                 {
285                         if (!IsTransparentProxy(proxy)) throw new RemotingException("Cannot get the real proxy from an object that is not a transparent proxy.");
286                         return (RealProxy)((TransparentProxy)proxy)._rp;
287                 }
288
289                 public static MethodBase GetMethodBaseFromMethodMessage(IMethodMessage msg)
290                 {
291                         Type type = Type.GetType (msg.TypeName);
292                         if (type == null)
293                                 throw new RemotingException ("Type '" + msg.TypeName + "' not found.");
294                                 
295                         return GetMethodBaseFromName (type, msg.MethodName, (Type[]) msg.MethodSignature);
296                 }
297                 
298                 internal static MethodBase GetMethodBaseFromName (Type type, string methodName, Type[] signature)
299                 {
300                         if (type.IsInterface) {
301                                 return FindInterfaceMethod (type, methodName, signature);
302                         }
303                         else {
304                                 MethodBase method = null;
305                                 if (signature == null)
306                                         method = type.GetMethod (methodName, methodBindings);
307                                 else
308                                         method = type.GetMethod (methodName, methodBindings, null, (Type[]) signature, null);
309                                 
310                                 if (method != null) 
311                                         return method;
312                                 
313                                 if (signature == null)
314                                         return type.GetConstructor (methodBindings, null, Type.EmptyTypes, null);
315                                 else
316                                         return type.GetConstructor (methodBindings, null, signature, null);
317                         }
318                 }
319                 
320                 static MethodBase FindInterfaceMethod (Type type, string methodName, Type[] signature)
321                 {
322                         MethodBase method = null;
323                         
324                         if (signature == null)
325                                 method = type.GetMethod (methodName, methodBindings);
326                         else
327                                 method = type.GetMethod (methodName, methodBindings, null, signature, null);
328                                 
329                         if (method != null) return method;
330                         
331                         foreach (Type t in type.GetInterfaces ()) {
332                                 method = FindInterfaceMethod (t, methodName, signature);
333                                 if (method != null) return method;
334                         }
335                         
336                         return null;
337                 }
338
339                 public static void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
340                 {
341                         if (obj == null) throw new ArgumentNullException ("obj");
342
343                         ObjRef oref = Marshal ((MarshalByRefObject)obj);
344                         oref.GetObjectData (info, context);
345                 }
346
347                 public static ObjRef GetObjRefForProxy(MarshalByRefObject obj)
348                 {
349                         Identity ident = GetObjectIdentity(obj);
350                         if (ident == null) return null;
351                         else return ident.CreateObjRef(null);
352                 }
353
354                 public static object GetLifetimeService (MarshalByRefObject obj)
355                 {
356                         if (obj == null) return null;
357                         return obj.GetLifetimeService ();
358                 }
359
360                 public static IMessageSink GetEnvoyChainForProxy (MarshalByRefObject obj)
361                 {
362                         if (IsTransparentProxy(obj))
363                                 return ((ClientIdentity)GetRealProxy (obj).ObjectIdentity).EnvoySink;
364                         else
365                                 throw new ArgumentException ("obj must be a proxy.","obj");                     
366                 }
367
368                 [MonoTODO]
369                 [Conditional ("REMOTING_PERF")]
370                 public static void LogRemotingStage (int stage)
371                 {
372                         throw new NotImplementedException ();
373                 }
374
375                 public static string GetSessionIdForMethodMessage(IMethodMessage msg)
376                 {
377                         // It seems that this it what MS returns.
378                         return msg.Uri;
379                 }
380
381                 public static bool IsMethodOverloaded(IMethodMessage msg)
382                 {
383                         // TODO: use internal call for better performance
384                         Type type = msg.MethodBase.DeclaringType;
385                         MemberInfo[] members = type.GetMember (msg.MethodName, MemberTypes.Method, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
386                         return members.Length > 1;
387                 }
388
389                 public static bool IsObjectOutOfAppDomain(object tp)
390                 {
391                         // TODO: use internal call for better performance
392                         Identity ident = GetObjectIdentity((MarshalByRefObject)tp);
393                         if (ident != null) return !ident.IsFromThisAppDomain;
394                         else return false;
395                 }
396
397                 public static bool IsObjectOutOfContext(object tp)
398                 {
399                         // TODO: use internal call for better performance
400                         ServerIdentity ident = GetObjectIdentity((MarshalByRefObject)tp) as ServerIdentity;
401                         if (ident != null) return ident.Context != System.Threading.Thread.CurrentContext;
402                         else return false;
403                 }
404
405                 public static bool IsOneWay(MethodBase method)
406                 {
407                         // TODO: use internal call for better performance
408                         object[] atts = method.GetCustomAttributes (typeof (OneWayAttribute), false);
409                         return atts.Length > 0;
410                 }
411
412                 internal static bool IsAsyncMessage(IMessage msg)
413                 {
414                         if (! (msg is MonoMethodMessage)) return false;
415                         else if (((MonoMethodMessage)msg).IsAsync) return true;
416                         else if (IsOneWay (((MonoMethodMessage)msg).MethodBase)) return true;
417                         else return false;
418                 }
419
420                 public static void SetObjectUriForMarshal(MarshalByRefObject obj, string uri)
421                 {
422                         if (IsTransparentProxy (obj)) throw new RemotingException ("SetObjectUriForMarshal method should only be called for MarshalByRefObjects that exist in the current AppDomain.");
423                         Marshal (obj, uri);
424                 }
425
426                 #region Internal Methods
427                 
428                 internal static object CreateClientProxy (ActivatedClientTypeEntry entry, object[] activationAttributes)
429                 {
430                         if (entry.ContextAttributes != null || activationAttributes != null)
431                         {
432                                 ArrayList props = new ArrayList ();
433                                 if (entry.ContextAttributes != null) props.AddRange (entry.ContextAttributes);
434                                 if (activationAttributes != null) props.AddRange (activationAttributes);
435                                 return CreateClientProxy (entry.ObjectType, entry.ApplicationUrl, props.ToArray ());
436                         }
437                         else
438                                 return CreateClientProxy (entry.ObjectType, entry.ApplicationUrl, null);
439                 }
440         
441                 internal static object CreateClientProxy (Type objectType, string url, object[] activationAttributes)
442                 {
443                         string activationUrl = url + "/RemoteActivationService.rem";
444
445                         string objectUri;
446                         IMessageSink sink = GetClientChannelSinkChain (activationUrl, null, out objectUri);
447
448                         RemotingProxy proxy = new RemotingProxy (objectType, activationUrl, activationAttributes);
449                         return proxy.GetTransparentProxy();
450                 }
451         
452                 internal static object CreateClientProxy (WellKnownClientTypeEntry entry)
453                 {
454                         return Connect (entry.ObjectType, entry.ObjectUrl, null);
455                 }
456         
457                 internal static object CreateClientProxyForContextBound (Type type, object[] activationAttributes)
458                 {
459                         if (type.IsContextful)
460                         {
461                                 // Look for a ProxyAttribute
462                                 ProxyAttribute att = (ProxyAttribute) Attribute.GetCustomAttribute (type, typeof(ProxyAttribute), true);
463                                 if (att != null)
464                                         return att.CreateInstance (type);
465                         }
466                         RemotingProxy proxy = new RemotingProxy (type, ChannelServices.CrossContextUrl, activationAttributes);
467                         return proxy.GetTransparentProxy();
468                 }
469         
470                 internal static Identity GetIdentityForUri (string uri)
471                 {
472                         lock (uri_hash)
473                         {
474                                 return (Identity)uri_hash [GetNormalizedUri(uri)];
475                         }
476                 }
477
478                 internal static Identity GetObjectIdentity (MarshalByRefObject obj)
479                 {
480                         if (IsTransparentProxy(obj))
481                                 return GetRealProxy (obj).ObjectIdentity;
482                         else
483                                 return obj.ObjectIdentity;
484                 }
485
486                 internal static ClientIdentity GetOrCreateClientIdentity(ObjRef objRef, Type proxyType, out object clientProxy)
487                 {
488                         // This method looks for an identity for the given url. 
489                         // If an identity is not found, it creates the identity and 
490                         // assigns it a proxy to the remote object.
491
492                         // Creates the client sink chain for the given url or channelData.
493                         // It will also get the object uri from the url.
494
495                         object channelData = objRef.ChannelInfo != null ? objRef.ChannelInfo.ChannelData : null;
496                         string url = (channelData == null) ? objRef.URI : null;
497
498                         string objectUri;
499                         IMessageSink sink = GetClientChannelSinkChain (url, channelData, out objectUri);
500
501                         if (objectUri == null) objectUri = objRef.URI;
502
503                         lock (uri_hash)
504                         {
505                                 clientProxy = null;
506                                 string uri = GetNormalizedUri (objRef.URI);
507                                 
508                                 ClientIdentity identity = uri_hash [uri] as ClientIdentity;
509                                 if (identity != null)
510                                 {
511                                         // Object already registered
512                                         clientProxy = identity.ClientProxy;
513                                         if (clientProxy != null) return identity;
514                                         
515                                         // The proxy has just been GCed, so its identity cannot
516                                         // be reused. Just dispose it.
517                                         DisposeIdentity (identity);
518                                 }
519
520                                 // Creates an identity and a proxy for the remote object
521
522                                 identity = new ClientIdentity (objectUri, objRef);
523                                 identity.ChannelSink = sink;
524
525                                 // Registers the identity
526                                 uri_hash [uri] = identity;
527                                 
528                                 if (proxyType != null)
529                                 {
530                                         RemotingProxy proxy = new RemotingProxy (proxyType, identity);
531                                         clientProxy = proxy.GetTransparentProxy();
532                                         identity.ClientProxy = (MarshalByRefObject) clientProxy;
533                                 }
534
535                                 return identity;
536                         }
537                 }
538
539                 static IMessageSink GetClientChannelSinkChain(string url, object channelData, out string objectUri)
540                 {
541                         IMessageSink sink = ChannelServices.CreateClientChannelSinkChain (url, channelData, out objectUri);
542                         if (sink == null) 
543                         {
544                                 if (url != null) 
545                                 {
546                                         string msg = String.Format ("Cannot create channel sink to connect to URL {0}. An appropriate channel has probably not been registered.", url); 
547                                         throw new RemotingException (msg);
548                                 }
549                                 else 
550                                 {
551                                         string msg = String.Format ("Cannot create channel sink to connect to the remote object. An appropriate channel has probably not been registered.", url); 
552                                         throw new RemotingException (msg);
553                                 }
554                         }
555                         return sink;
556                 }
557
558                 internal static ClientActivatedIdentity CreateContextBoundObjectIdentity(Type objectType)
559                 {
560                         ClientActivatedIdentity identity = new ClientActivatedIdentity (null, objectType);
561                         identity.ChannelSink = ChannelServices.CrossContextChannel;
562                         return identity;
563                 }
564
565                 internal static ClientActivatedIdentity CreateClientActivatedServerIdentity(MarshalByRefObject realObject, Type objectType, string objectUri)
566                 {
567                         ClientActivatedIdentity identity = new ClientActivatedIdentity (objectUri, objectType);
568                         identity.AttachServerObject (realObject, Context.DefaultContext);
569                         RegisterServerIdentity (identity);
570                         identity.StartTrackingLifetime ((ILease)realObject.InitializeLifetimeService ());
571                         return identity;
572                 }
573
574                 internal static ServerIdentity CreateWellKnownServerIdentity(Type objectType, string objectUri, WellKnownObjectMode mode)
575                 {
576                         ServerIdentity identity;
577
578                         if (mode == WellKnownObjectMode.SingleCall)
579                                 identity = new  SingleCallIdentity(objectUri, Context.DefaultContext, objectType);
580                         else
581                                 identity = new  SingletonIdentity(objectUri, Context.DefaultContext, objectType);
582
583                         RegisterServerIdentity (identity);
584                         return identity;
585                 }
586
587                 private static void RegisterServerIdentity(ServerIdentity identity)
588                 {
589                         lock (uri_hash)
590                         {
591                                 if (uri_hash.ContainsKey (identity.ObjectUri)) 
592                                         throw new RemotingException ("Uri already in use: " + identity.ObjectUri + ".");
593
594                                 uri_hash[identity.ObjectUri] = identity;
595                         }
596                 }
597
598                 internal static object GetProxyForRemoteObject (ObjRef objref, Type classToProxy)
599                 {
600                         ClientActivatedIdentity identity = GetIdentityForUri (objref.URI) as ClientActivatedIdentity;
601                         if (identity != null) return identity.GetServerObject ();
602                         else return GetRemoteObject (objref, classToProxy);
603                 }
604
605                 internal static object GetRemoteObject(ObjRef objRef, Type proxyType)
606                 {
607                         object proxy;
608                         GetOrCreateClientIdentity (objRef, proxyType, out proxy);
609                         return proxy;
610                 }
611
612                 internal static object GetDomainProxy(AppDomain domain) 
613                 {
614                         byte[] data = null;
615
616                         Context currentContext = Thread.CurrentContext;
617
618                         try
619                         {
620                                 data = (byte[])AppDomain.InvokeInDomain (domain, typeof (AppDomain).GetMethod ("GetMarshalledDomainObjRef", BindingFlags.Instance|BindingFlags.NonPublic), domain, null);
621                         }
622                         finally
623                         {
624                                 AppDomain.InternalSetContext (currentContext);
625                         }                               
626
627                         MemoryStream stream = new MemoryStream (data);
628                         ObjRef appref = (ObjRef) CADSerializer.DeserializeObject (stream);
629                         return (AppDomain) RemotingServices.Unmarshal(appref);
630                 }
631
632                 private static void RegisterInternalChannels() 
633                 {
634                         CrossAppDomainChannel.RegisterCrossAppDomainChannel();
635                 }
636                 
637                 internal static void DisposeIdentity (Identity ident)
638                 {
639                         lock (uri_hash)
640                         {
641                                 if (!ident.Disposed) {
642                                         ClientIdentity clientId = ident as ClientIdentity;
643                                         if (clientId != null)
644                                                 uri_hash.Remove (GetNormalizedUri (clientId.TargetUri));
645                                         else
646                                                 uri_hash.Remove (ident.ObjectUri);
647                                                 
648                                         ident.Disposed = true;
649                                 }
650                         }
651                 }
652
653                 internal static Identity GetMessageTargetIdentity (IMessage msg)
654                 {
655                         // Returns the identity where the message is sent
656
657                         if (msg is IInternalMessage) 
658                                 return ((IInternalMessage)msg).TargetIdentity;
659
660                         lock (uri_hash)
661                         {
662                                 string uri = GetNormalizedUri (((IMethodMessage)msg).Uri);
663                                 return uri_hash [uri] as ServerIdentity;
664                         }
665                 }
666
667                 internal static void SetMessageTargetIdentity (IMessage msg, Identity ident)
668                 {
669                         if (msg is IInternalMessage) 
670                                 ((IInternalMessage)msg).TargetIdentity = ident;
671                 }
672                 
673                 internal static bool UpdateOutArgObject (ParameterInfo pi, object local, object remote)
674                 {
675                         if (local is StringBuilder) 
676                         {
677                                 StringBuilder sb = local as StringBuilder;
678                                 sb.Remove (0, sb.Length);
679                                 sb.Append (remote.ToString());
680                                 return true;
681                         }
682                         else if (pi.ParameterType.IsArray && ((Array)local).Rank == 1)
683                         {
684                                 Array alocal = (Array) local;
685                                 if (alocal.Rank == 1)
686                                 {
687                                         Array.Copy ((Array) remote, alocal, alocal.Length);
688                                         return true;
689                                 }
690                                 else
691                                 {
692                                         // TODO
693                                 }
694                         }
695                         return false;
696                 }
697                 
698                 static string GetNormalizedUri (string uri)
699                 {
700                         if (uri.StartsWith ("/")) return uri.Substring (1);
701                         else return uri;
702                 }
703
704                 #endregion
705         }
706 }