2003-02-03 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[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 using System;
13 using System.Reflection;
14 using System.Threading;
15 using System.Collections;
16 using System.Runtime.Remoting.Messaging;
17 using System.Runtime.Remoting.Proxies;
18 using System.Runtime.Remoting.Channels;
19 using System.Runtime.Remoting.Contexts;
20 using System.Runtime.Remoting.Activation;
21 using System.Runtime.Remoting.Lifetime;
22 using System.Runtime.CompilerServices;
23 using System.Runtime.Serialization;
24
25 namespace System.Runtime.Remoting
26 {
27         public sealed class RemotingServices 
28         {
29                 // Holds the identities of the objects, using uri as index
30                 static Hashtable uri_hash = new Hashtable ();           
31
32                 internal static string app_id;
33                 static int next_id = 1;
34                 
35                 static RemotingServices ()
36                 {
37                         app_id = "/" + Guid.NewGuid().ToString().Replace('-', '_') + "/";
38
39                         CreateServerIdentity (null, typeof(RemoteActivator), "RemoteActivationService.rem", ServiceType.Singleton);
40                 }
41         
42                 private RemotingServices () {}
43
44                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
45                 internal extern static object InternalExecute (MonoMethod method, Object obj,
46                                                                Object[] parameters, out object [] out_args);
47
48                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
49                 public extern static bool IsTransparentProxy (object proxy);
50                 
51                 internal static IMethodReturnMessage InternalExecuteMessage (
52                         MarshalByRefObject target, IMethodCallMessage reqMsg)
53                 {
54                         ReturnMessage result;
55                         
56                         MonoMethod method = (MonoMethod)reqMsg.MethodBase;
57
58                         try {
59                                 object [] out_args;
60                                 object rval = InternalExecute (method, target, reqMsg.Args, out out_args);
61                                 result = new ReturnMessage (rval, out_args, out_args.Length,
62                                                             reqMsg.LogicalCallContext, reqMsg);
63                         
64                         } catch (Exception e) {
65                                 result = new ReturnMessage (e, reqMsg);
66                         }
67
68                         return result;
69                 }
70
71                 public static IMethodReturnMessage ExecuteMessage (
72                         MarshalByRefObject target, IMethodCallMessage reqMsg)
73                 {
74                         if (IsTransparentProxy(target))
75                         {
76                                 // Message must go through all chain of sinks
77                                 RealProxy rp = GetRealProxy (target);
78                                 return (IMethodReturnMessage) rp.Invoke (reqMsg);
79                         }
80                         else    // Direct call
81                                 return InternalExecuteMessage (target, reqMsg);
82                 }
83
84                 public static object Connect (Type classToProxy, string url)
85                 {
86                         return GetRemoteObject(classToProxy, url, null, null);
87                 }
88
89                 public static object Connect (Type classToProxy, string url, object data)
90                 {
91                         return GetRemoteObject (classToProxy, url, data, null);
92                 }
93
94                 public static Type GetServerTypeForUri (string uri)
95                 {
96                         Identity ident = GetIdentityForUri (uri);
97                         if (ident == null) return null;
98                         return ident.ObjectType;
99                 }
100
101                 public static string GetObjectUri (MarshalByRefObject obj)
102                 {
103                         Identity ident = GetObjectIdentity(obj);
104                         if (ident != null) return ident.ObjectUri;
105                         else return null;
106                 }
107
108                 public static object Unmarshal (ObjRef objref)
109                 {
110                         return Unmarshal(objref, false);
111                 }
112
113                 public static object Unmarshal (ObjRef objref, bool fRefine)
114                 {
115                         // FIXME: use type name when fRefine==true
116                         Type requiredType = Type.GetType(objref.TypeInfo.TypeName);
117                         return GetRemoteObject(requiredType, null, objref.ChannelInfo.ChannelData, objref.URI);
118                 }
119
120                 public static ObjRef Marshal (MarshalByRefObject obj)
121                 {
122                         return Marshal (obj, null, null);
123                 }
124                 
125                 public static ObjRef Marshal (MarshalByRefObject obj, string uri)
126                 {
127                         return Marshal (obj, uri, null);
128                 }
129                 
130                 public static ObjRef Marshal (MarshalByRefObject obj, string uri, Type requested_type)
131                 {
132                         if (IsTransparentProxy (obj))
133                         {
134                                 RealProxy proxy = RemotingServices.GetRealProxy(obj);
135                                 if (proxy != null && proxy.ObjectIdentity != null)
136                                 {
137                                         if (uri != null)
138                                                 throw new RemotingException ("It is not possible marshal a proxy of a remote object");
139
140                                         return proxy.ObjectIdentity.CreateObjRef(requested_type);
141                                 }
142                         }
143
144                         if (requested_type == null) requested_type = obj.GetType();
145                         if (uri == null) uri = app_id + Environment.TickCount + "_" + next_id++;
146
147                         CreateServerIdentity (obj, requested_type, uri, ServiceType.ClientActivated);
148                         return obj.CreateObjRef(requested_type);
149                 }
150
151                 public static RealProxy GetRealProxy (object proxy)
152                 {
153                         if (!IsTransparentProxy(proxy)) throw new RemotingException("Cannot get the real proxy from an object that is not a transparent proxy");
154                         return (RealProxy)((TransparentProxy)proxy)._rp;
155                 }
156
157                 public static MethodBase GetMethodBaseFromMethodMessage(IMethodMessage msg)
158                 {
159                         Type type = Type.GetType (msg.TypeName);
160                         if (type == null)
161                                 throw new RemotingException ("Type '" + msg.TypeName + "' not found!");
162
163                         BindingFlags bflags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
164                         if (msg.MethodSignature == null)
165                                 return type.GetMethod (msg.MethodName, bflags);
166                         else
167                                 return type.GetMethod (msg.MethodName, bflags, null, (Type[]) msg.MethodSignature, null);
168                 }
169
170                 public static void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
171                 {
172                         if (obj == null) throw new ArgumentNullException ("obj");
173
174                         MarshalByRefObject mbr = (MarshalByRefObject)obj;
175
176                         ObjRef oref;
177                         Identity ident = GetObjectIdentity(mbr);
178
179                         if (ident != null)
180                                 oref = mbr.CreateObjRef(null);
181                         else
182                                 oref = Marshal (mbr);
183
184                         oref.GetObjectData (info, context);
185                 }
186
187                 public static ObjRef GetObjRefForProxy(MarshalByRefObject obj)
188                 {
189                         Identity ident = GetObjectIdentity(obj);
190                         if (ident == null) return null;
191                         else return ident.CreateObjRef(null);
192                 }
193
194                 [MonoTODO]
195                 public static string GetSessionIdForMethodMessage(IMethodMessage msg)
196                 {
197                         throw new NotImplementedException (); 
198                 }
199
200                 public static bool IsMethodOverloaded(IMethodMessage msg)
201                 {
202                         Type type = msg.MethodBase.DeclaringType;
203                         MemberInfo[] members = type.GetMember (msg.MethodName, MemberTypes.Method, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);\r
204                         return members.Length > 1;\r
205                 }
206
207                 public static bool IsObjectOutOfAppDomain(object tp)
208                 {
209                         Identity ident = GetObjectIdentity((MarshalByRefObject)tp);
210                         if (ident != null) return !ident.IsFromThisAppDomain;
211                         else return false;
212                 }
213
214                 public static bool IsObjectOutOfContext(object tp)
215                 {
216                         Identity ident = GetObjectIdentity((MarshalByRefObject)tp);
217                         if (ident != null) return ident.Context != System.Threading.Thread.CurrentContext;
218                         else return false;
219                 }
220
221                 public static bool IsOneWay(MethodBase method)
222                 {
223                         object[] atts = method.GetCustomAttributes (typeof (OneWayAttribute), false);
224                         return atts.Length > 0;
225                 }
226
227                 public static void SetObjectUriForMarshal(MarshalByRefObject obj, string uri)
228                 {
229                         if (IsTransparentProxy (obj)) throw new RemotingException ("SetObjectUriForMarshal method should only be called for MarshalByRefObjects that exist in the current AppDomain.");
230                         Marshal (obj, uri);
231                 }
232
233                 #region Internal Methods
234                 
235                 internal static Identity GetIdentityForUri (string uri)
236                 {
237                         lock (uri_hash)
238                         {
239                                 return (Identity)uri_hash [uri];
240                         }
241                 }
242
243                 internal static Identity GetObjectIdentity (MarshalByRefObject obj)
244                 {
245                         if (IsTransparentProxy(obj))
246                                 return GetRealProxy (obj).ObjectIdentity;
247                         else
248                                 return obj.ObjectIdentity;
249                 }
250
251                 private static Identity GetClientIdentity(Type requiredType, string url, object channelData, string remotedObjectUri)
252                 {
253                         // This method looks for an identity for the given url. 
254                         // If an identity is not found, it creates the identity and 
255                         // assigns it a proxy to the remote object.
256
257                         // Creates the client sink chain for the given url or channelData.
258                         // It will also get the object uri from the url.
259
260                         string objectUri;
261                         IMessageSink sink = ChannelServices.CreateClientChannelSinkChain (url, channelData, out objectUri);
262                         if (sink == null) 
263                         {
264                                 if (url != null) {
265                                         string msg = String.Format ("Cannot create channel sink to connect to URL {0}. An appropriate channel has probably not been registered.", url); 
266                                         throw new RemotingException (msg);
267                                 }
268                                 else {
269                                         string msg = String.Format ("Cannot create channel sink to connect to the remote object. An appropriate channel has probably not been registered.", url); 
270                                         throw new RemotingException (msg);
271                                 }
272                         }
273
274                         if (objectUri == null) objectUri = remotedObjectUri;
275
276                         lock (uri_hash)
277                         {
278                                 Identity identity = (Identity)uri_hash [objectUri];
279                                 if (identity != null) 
280                                         return identity;        // Object already registered
281
282                                 // Creates an identity and a proxy for the remote object
283
284                                 identity = new Identity (objectUri, null, requiredType, ServiceType.ClientProxy);
285                                 identity.ClientSink = sink;
286
287                                 RemotingProxy proxy = new RemotingProxy (requiredType, identity);
288
289                                 identity.RealObject = (MarshalByRefObject) proxy.GetTransparentProxy();
290
291                                 // Registers the identity
292                                 uri_hash [objectUri] = identity;
293                                 return identity;
294                         }
295                 }
296
297                 internal static Identity CreateServerIdentity(MarshalByRefObject realObject, Type objectType, string objectUri, ServiceType serviceType)
298                 {
299                         // This method looks for an identity for the given object. 
300                         // If an identity is not found, it creates the identity and 
301                         // assigns it to the given object
302
303                         lock (uri_hash)
304                         {
305                                 Identity identity = (Identity)uri_hash [objectUri];
306                                 if (identity != null) 
307                                 {
308                                         if (realObject != identity.RealObject)
309                                                 throw new RemotingException ("Uri already in use: " + objectUri);
310
311                                         return identity;        // Object already registered
312                                 }
313
314                                 identity = new Identity (objectUri, Context.DefaultContext, objectType, serviceType);
315                                 identity.RealObject = realObject;
316
317                                 // Registers the identity
318                                 uri_hash[objectUri] = identity;
319
320                                 if (realObject != null)
321                                         realObject.ObjectIdentity = identity;
322
323                                 LifetimeServices.TrackLifetime (identity);
324
325                                 return identity;
326                         }
327                 }
328
329                 internal static object GetRemoteObject(Type requiredType, string url, object channelData, string remotedObjectUri)
330                 {
331                         Identity id = GetClientIdentity(requiredType, url, channelData, remotedObjectUri);
332                         return id.RealObject;
333                 }
334
335                 internal static object GetDomainProxy(AppDomain domain) \r
336                 {\r
337                         ObjRef appRef = null;\r
338 \r
339                         // Make sure that the channels is active in this domain\r
340                         RegisterInternalChannels();\r
341 \r
342                         // this should use contexts in the future\r
343                         AppDomain currentDomain = AppDomain.InternalSetDomain (domain);\r
344                         try \r
345                         {\r
346                                 // Make sure that our new domain also has the internal channels\r
347                                 RegisterInternalChannels();\r
348 \r
349                                 appRef = RemotingServices.Marshal(domain, null, null);\r
350                         }\r
351                         finally \r
352                         {\r
353                                 AppDomain.InternalSetDomain (currentDomain);\r
354                         }\r
355 \r
356                         return (AppDomain) RemotingServices.Unmarshal(appRef);\r
357                 }\r
358 \r
359 \r
360                 private static void RegisterInternalChannels() \r
361                 {\r
362                         CrossAppDomainChannel.RegisterCrossAppDomainChannel();\r
363                 }
364
365                 
366                 internal static void DisposeObject (MarshalByRefObject obj)
367                 {
368                         IDisposable disp = obj as IDisposable;
369                         if (disp != null) disp.Dispose ();
370
371                         Identity ident = GetObjectIdentity (obj);
372                         if (ident == null) return;
373                         else uri_hash.Remove (ident.ObjectUri);
374                 }
375
376                 #endregion      
377         }
378 }