copying the latest Sys.Web.Services from trunk.
[mono.git] / mcs / class / corlib / System.Runtime.Remoting.Messaging / CADMessages.cs
1 //
2 // System.Runtime.Remoting.Messaging.CADMessages.cs
3 //
4 // Author:
5 //   Patrik Torstensson
6 //
7 // (C) Patrik Torstensson
8 //
9
10 //
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System;
34 using System.Collections;
35 using System.IO;
36 using System.Runtime.Serialization;
37 using System.Runtime.Remoting;
38 using System.Runtime.Remoting.Channels;
39 using System.Runtime.Remoting.Messaging;
40 using System.Runtime.Remoting.Proxies;
41
42 namespace System.Runtime.Remoting.Messaging {
43
44         internal class CADArgHolder {
45                 public int index;
46
47                 public CADArgHolder (int i) {
48                         index = i;
49                 }
50         }
51         
52         internal class CADObjRef {
53                 ObjRef objref;
54                 public int SourceDomain;
55
56                 public CADObjRef (ObjRef o, int sourceDomain) {
57                         objref = o;
58                         SourceDomain = sourceDomain;
59                 }
60                 
61                 public string TypeName {
62                         get { return objref.TypeInfo.TypeName; }
63                 }
64                 
65                 public string URI {
66                         get { return objref.URI; }
67                 }
68         }
69
70         internal class CADMessageBase {
71
72                 protected object [] _args;
73                 protected byte [] _serializedArgs = null;
74                 protected int _propertyCount = 0;
75                 protected CADArgHolder _callContext;
76                 
77                 // Helper to marshal properties
78                 internal static int MarshalProperties (IDictionary dict, ref ArrayList args) {
79                         IDictionary serDict = dict;
80                         int count = 0;
81
82                         MethodDictionary msgDict = dict as MethodDictionary;
83                         if (null != msgDict) {
84                                 if (msgDict.HasInternalProperties) {
85                                         serDict = msgDict.InternalProperties;
86                                         if (null != serDict) {
87                                                 foreach (DictionaryEntry e in serDict) {
88                                                         if (null == args)
89                                                                 args = new ArrayList();
90                                                         args.Add(e);
91                                                         count++;
92                                                 }
93                                         }
94                                 }
95                         } else {
96                                 if (null != dict) {
97                                         foreach (DictionaryEntry e in serDict) {
98                                                 if (null == args)
99                                                         args = new ArrayList();
100                                                 args.Add(e);
101                                                 count++;
102                                         }
103                                 }
104                         }
105
106                         return count;
107                 }
108
109                 internal static void UnmarshalProperties (IDictionary dict, int count, ArrayList args) {
110                         for (int i = 0; i < count; i++) {
111                                 DictionaryEntry e = (DictionaryEntry) args [i];
112                                 dict [e.Key] = e.Value;
113                         }
114                 }
115
116                 // We can ignore marshalling for string and primitive types
117                 private static bool IsPossibleToIgnoreMarshal (object obj) {
118
119                         Type objType = obj.GetType();
120                         if (objType.IsPrimitive || objType == typeof(void))
121                                 return true;
122                         
123                         if (objType.IsArray && objType.GetElementType().IsPrimitive && ((Array)obj).Rank == 1)
124                                 return true;
125                                 
126                         if (obj is string || obj is DateTime || obj is TimeSpan)
127                                 return true;
128                                 
129                         return false;
130                 }
131
132                 // Checks an argument if it's possible to pass without marshalling and
133                 // if not it will be added to arguments to be serialized
134                 protected object MarshalArgument (object arg, ref ArrayList args) {
135                         if (null == arg)
136                                 return null;
137
138                         if (IsPossibleToIgnoreMarshal (arg))
139                                 return arg;
140
141                         MarshalByRefObject mbr = arg as MarshalByRefObject;
142                         if (null != mbr)
143                         {
144                                 if (RemotingServices.IsTransparentProxy(mbr)) {
145                                         // We don't deal with this case yet
146                                 }
147                                 else {
148                                         ObjRef objRef = RemotingServices.Marshal(mbr);
149                                         return new CADObjRef(objRef, System.Threading.Thread.GetDomainID());
150                                 }
151                         }
152
153                         if (null == args)
154                                 args = new ArrayList();
155                         
156                         args.Add (arg);
157                         
158                         // return position that the arg exists in the serialized list
159                         return new CADArgHolder(args.Count - 1);
160                 }
161
162                 protected object UnmarshalArgument (object arg, ArrayList args) {
163                         if (arg == null) return null;
164                         
165                         // Check if argument is an holder (then we know that it's a serialized argument)
166                         CADArgHolder holder = arg as CADArgHolder;
167                         if (null != holder) {
168                                 return args [holder.index];
169                         }
170
171                         CADObjRef objref = arg as CADObjRef;
172                         if (null != objref) {
173                                 string typeName = string.Copy (objref.TypeName);
174                                 string uri = string.Copy (objref.URI);
175                                 int domid = objref.SourceDomain;
176                                 
177                                 ChannelInfo cinfo = new ChannelInfo (new CrossAppDomainData (domid));
178                                 ObjRef localRef = new ObjRef (typeName, uri, cinfo);
179                                 return RemotingServices.Unmarshal (localRef);
180                         }
181                         
182                         if (arg is Array)
183                         {
184                                 Array argb = (Array)arg;
185                                 Array argn;
186                                 
187                                 // We can't use Array.CreateInstance (arg.GetType().GetElementType()) because
188                                 // GetElementType() returns a type from the source domain.
189                                 
190                                 switch (Type.GetTypeCode (arg.GetType().GetElementType()))
191                                 {
192                                         case TypeCode.Boolean: argn = new bool [argb.Length]; break;
193                                         case TypeCode.Byte: argn = new Byte [argb.Length]; break;
194                                         case TypeCode.Char: argn = new Char [argb.Length]; break;
195                                         case TypeCode.Decimal: argn = new Decimal [argb.Length]; break;
196                                         case TypeCode.Double: argn = new Double [argb.Length]; break;
197                                         case TypeCode.Int16: argn = new Int16 [argb.Length]; break;
198                                         case TypeCode.Int32: argn = new Int32 [argb.Length]; break;
199                                         case TypeCode.Int64: argn = new Int64 [argb.Length]; break;
200                                         case TypeCode.SByte: argn = new SByte [argb.Length]; break;
201                                         case TypeCode.Single: argn = new Single [argb.Length]; break;
202                                         case TypeCode.UInt16: argn = new UInt16 [argb.Length]; break;
203                                         case TypeCode.UInt32: argn = new UInt32 [argb.Length]; break;
204                                         case TypeCode.UInt64: argn = new UInt64 [argb.Length]; break;
205                                         default: throw new NotSupportedException ();
206                                 }
207                                 
208                                 argb.CopyTo (argn, 0);
209                                 return argn;
210                         }
211
212                         switch (Type.GetTypeCode (arg.GetType()))
213                         {
214                                 case TypeCode.Boolean: return (bool)arg;
215                                 case TypeCode.Byte: return (byte)arg;
216                                 case TypeCode.Char: return (char)arg;
217                                 case TypeCode.Decimal: return (decimal)arg;
218                                 case TypeCode.Double: return (double)arg;
219                                 case TypeCode.Int16: return (Int16)arg;
220                                 case TypeCode.Int32: return (Int32)arg;
221                                 case TypeCode.Int64: return (Int64)arg;
222                                 case TypeCode.SByte: return (SByte)arg;
223                                 case TypeCode.Single: return (Single)arg;
224                                 case TypeCode.UInt16: return (UInt16)arg;
225                                 case TypeCode.UInt32: return (UInt32)arg;
226                                 case TypeCode.UInt64: return (UInt64)arg;
227                                 case TypeCode.String: return string.Copy ((string) arg);
228                                 case TypeCode.DateTime: return new DateTime (((DateTime)arg).Ticks);
229                                 default:
230                                         if (arg is TimeSpan) return new TimeSpan (((TimeSpan)arg).Ticks);
231                                         break;
232                         }       
233
234                         throw new NotSupportedException ("Parameter of type " + arg.GetType () + " cannot be unmarshalled");
235                 }
236
237                 internal object [] MarshalArguments (object [] arguments, ref ArrayList args) {
238                         object [] marshalledArgs = new object [arguments.Length];
239
240                         int total = arguments.Length;
241                         for (int i = 0; i < total; i++)
242                                 marshalledArgs [i] = MarshalArgument (arguments [i], ref args);
243
244                         return marshalledArgs;
245                 }
246
247                 internal object [] UnmarshalArguments (object [] arguments, ArrayList args) {
248                         object [] unmarshalledArgs = new object [arguments.Length];
249
250                         int total = arguments.Length;
251                         for (int i = 0; i < total; i++)
252                                 unmarshalledArgs [i] = UnmarshalArgument (arguments [i], args);
253
254                         return unmarshalledArgs;
255                 }
256                 
257                 protected void SaveLogicalCallContext (IMethodMessage msg, ref ArrayList serializeList)
258                 {
259                         if (msg.LogicalCallContext != null && msg.LogicalCallContext.HasInfo) 
260                         {
261                                 if (serializeList == null)
262                                         serializeList = new ArrayList();
263
264                                 _callContext = new CADArgHolder (serializeList.Count);
265                                 serializeList.Add (msg.LogicalCallContext);
266                         }
267                 }
268                 
269                 internal LogicalCallContext GetLogicalCallContext (ArrayList args) 
270                 {
271                         if (null == _callContext)
272                                 return null;
273
274                         return (LogicalCallContext) args [_callContext.index];
275                 }
276         }
277
278         // Used when passing a IMethodCallMessage between appdomains
279         internal class CADMethodCallMessage : CADMessageBase {
280                 string _uri;
281                 
282                 internal RuntimeMethodHandle MethodHandle;
283                 
284                 internal string Uri {
285                         get {
286                                 return _uri;
287                         }
288                 }
289
290                 static internal CADMethodCallMessage Create (IMessage callMsg) {
291                         IMethodCallMessage msg = callMsg as IMethodCallMessage;
292                         if (null == msg)
293                                 return null;
294
295                         return new CADMethodCallMessage (msg);
296                 }
297
298                 internal CADMethodCallMessage (IMethodCallMessage callMsg) {
299                         _uri = callMsg.Uri;
300                         MethodHandle = callMsg.MethodBase.MethodHandle;
301
302                         ArrayList serializeList = null; 
303                         
304                         _propertyCount = MarshalProperties (callMsg.Properties, ref serializeList);
305
306                         _args = MarshalArguments ( callMsg.Args, ref serializeList);
307
308                         // Save callcontext
309                         SaveLogicalCallContext (callMsg, ref serializeList);
310                         
311                         // Serialize message data if needed
312
313                         if (null != serializeList) {
314                                 MemoryStream stm = CADSerializer.SerializeObject (serializeList.ToArray());
315                                 _serializedArgs = stm.GetBuffer();
316                         }
317                 }
318
319                 internal ArrayList GetArguments () {
320                         ArrayList ret = null;
321
322                         if (null != _serializedArgs) {
323                                 object[] oret = (object[]) CADSerializer.DeserializeObject (new MemoryStream (_serializedArgs));
324                                 ret = new ArrayList (oret);
325                                 _serializedArgs = null;
326                         }
327
328                         return ret;
329                 }
330
331                 internal object [] GetArgs (ArrayList args) {
332                         return UnmarshalArguments (_args, args);
333                 }
334
335                 internal int PropertiesCount {
336                         get {
337                                 return _propertyCount;
338                         }
339                 }
340         }
341         
342         // Used when passing a IMethodReturnMessage between appdomains
343         internal class CADMethodReturnMessage : CADMessageBase {
344                 object _returnValue;
345                 CADArgHolder _exception = null;
346
347                 static internal CADMethodReturnMessage Create (IMessage callMsg) {
348                         IMethodReturnMessage msg = callMsg as IMethodReturnMessage;
349                         if (null == msg)
350                                 return null;
351
352                         return new CADMethodReturnMessage (msg);
353                 }
354
355                 internal CADMethodReturnMessage(IMethodReturnMessage retMsg) {
356                         ArrayList serializeList = null; 
357                         
358                         _propertyCount = MarshalProperties (retMsg.Properties, ref serializeList);
359
360                         _returnValue = MarshalArgument ( retMsg.ReturnValue, ref serializeList);
361                         _args = MarshalArguments ( retMsg.Args, ref serializeList);
362
363                         if (null != retMsg.Exception) {
364                                 if (null == serializeList)
365                                         serializeList = new ArrayList();
366                                 
367                                 _exception = new CADArgHolder (serializeList.Count);
368                                 serializeList.Add(retMsg.Exception);
369                         }
370
371                         // Save callcontext
372                         SaveLogicalCallContext (retMsg, ref serializeList);
373
374                         if (null != serializeList) {
375                                 MemoryStream stm = CADSerializer.SerializeObject (serializeList.ToArray());
376                                 _serializedArgs = stm.GetBuffer();
377                         }
378                 }
379
380                 internal ArrayList GetArguments () {
381                         ArrayList ret = null;
382
383                         if (null != _serializedArgs) {
384                                 object[] oret = (object[]) CADSerializer.DeserializeObject (new MemoryStream (_serializedArgs));
385                                 ret = new ArrayList (oret);
386                                 _serializedArgs = null;
387                         }
388
389                         return ret;
390                 }
391
392                 internal object [] GetArgs (ArrayList args) {
393                         return UnmarshalArguments (_args, args);
394                 }
395                         
396                 internal object GetReturnValue (ArrayList args) {
397                         return UnmarshalArgument (_returnValue, args);
398                 }
399
400                 internal Exception GetException(ArrayList args) {
401                         if (null == _exception)
402                                 return null;
403
404                         return (Exception) args [_exception.index]; 
405                 }
406
407                 internal int PropertiesCount {
408                         get {
409                                 return _propertyCount;
410                         }
411                 }
412         }
413 }