* WebService.cs: Added SoapVersion property.
[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 = new string (objref.TypeName.ToCharArray());
174                                 string uri = new string (objref.URI.ToCharArray());
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 new String (((string)arg).ToCharArray());
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                 string _methodName;
282                 string _typeName;
283
284                 CADArgHolder _methodSignature;
285
286                 internal string TypeName {
287                         get {
288                                 return _typeName;
289                         }
290                 }
291
292                 internal string Uri {
293                         get {
294                                 return _uri;
295                         }
296                 }
297
298                 internal string MethodName {
299                         get {
300                                 return _methodName;
301                         }
302                 }
303
304                 static internal CADMethodCallMessage Create (IMessage callMsg) {
305                         IMethodCallMessage msg = callMsg as IMethodCallMessage;
306                         if (null == msg)
307                                 return null;
308
309                         return new CADMethodCallMessage (msg);
310                 }
311
312                 internal CADMethodCallMessage (IMethodCallMessage callMsg) {
313                         _methodName = callMsg.MethodName;
314                         _typeName = callMsg.TypeName;
315                         _uri = callMsg.Uri;
316
317                         ArrayList serializeList = null; 
318                         
319                         _propertyCount = MarshalProperties (callMsg.Properties, ref serializeList);
320
321                         _args = MarshalArguments ( callMsg.Args, ref serializeList);
322
323                         // check if we need to save method signature
324                         if (RemotingServices.IsMethodOverloaded (callMsg)) {
325                                 if (null == serializeList)
326                                         serializeList = new ArrayList();
327
328                                 _methodSignature = new CADArgHolder (serializeList.Count);
329                                 serializeList.Add(callMsg.MethodSignature);
330                         }
331
332                         // Save callcontext
333                         SaveLogicalCallContext (callMsg, ref serializeList);
334                         
335                         // Serialize message data if needed
336
337                         if (null != serializeList) {
338                                 MemoryStream stm = CADSerializer.SerializeObject (serializeList.ToArray());
339                                 _serializedArgs = stm.GetBuffer();
340                         }
341                 }
342
343                 internal ArrayList GetArguments () {
344                         ArrayList ret = null;
345
346                         if (null != _serializedArgs) {
347                                 object[] oret = (object[]) CADSerializer.DeserializeObject (new MemoryStream (_serializedArgs));
348                                 ret = new ArrayList (oret);
349                                 _serializedArgs = null;
350                         }
351
352                         return ret;
353                 }
354
355                 internal object [] GetArgs (ArrayList args) {
356                         return UnmarshalArguments (_args, args);
357                 }
358                         
359                 internal object [] GetMethodSignature (ArrayList args) {
360                         if (null == _methodSignature)
361                                 return null;
362
363                         return (object []) args [_methodSignature.index];
364                 }
365
366                 internal int PropertiesCount {
367                         get {
368                                 return _propertyCount;
369                         }
370                 }
371         }
372         
373         // Used when passing a IMethodReturnMessage between appdomains
374         internal class CADMethodReturnMessage : CADMessageBase {
375                 object _returnValue;
376                 CADArgHolder _exception = null;
377
378                 static internal CADMethodReturnMessage Create (IMessage callMsg) {
379                         IMethodReturnMessage msg = callMsg as IMethodReturnMessage;
380                         if (null == msg)
381                                 return null;
382
383                         return new CADMethodReturnMessage (msg);
384                 }
385
386                 internal CADMethodReturnMessage(IMethodReturnMessage retMsg) {
387                         ArrayList serializeList = null; 
388                         
389                         _propertyCount = MarshalProperties (retMsg.Properties, ref serializeList);
390
391                         _returnValue = MarshalArgument ( retMsg.ReturnValue, ref serializeList);
392                         _args = MarshalArguments ( retMsg.Args, ref serializeList);
393
394                         if (null != retMsg.Exception) {
395                                 if (null == serializeList)
396                                         serializeList = new ArrayList();
397                                 
398                                 _exception = new CADArgHolder (serializeList.Count);
399                                 serializeList.Add(retMsg.Exception);
400                         }
401
402                         // Save callcontext
403                         SaveLogicalCallContext (retMsg, ref serializeList);
404
405                         if (null != serializeList) {
406                                 MemoryStream stm = CADSerializer.SerializeObject (serializeList.ToArray());
407                                 _serializedArgs = stm.GetBuffer();
408                         }
409                 }
410
411                 internal ArrayList GetArguments () {
412                         ArrayList ret = null;
413
414                         if (null != _serializedArgs) {
415                                 object[] oret = (object[]) CADSerializer.DeserializeObject (new MemoryStream (_serializedArgs));
416                                 ret = new ArrayList (oret);
417                                 _serializedArgs = null;
418                         }
419
420                         return ret;
421                 }
422
423                 internal object [] GetArgs (ArrayList args) {
424                         return UnmarshalArguments (_args, args);
425                 }
426                         
427                 internal object GetReturnValue (ArrayList args) {
428                         return UnmarshalArgument (_returnValue, args);
429                 }
430
431                 internal Exception GetException(ArrayList args) {
432                         if (null == _exception)
433                                 return null;
434
435                         return (Exception) args [_exception.index]; 
436                 }
437
438                 internal int PropertiesCount {
439                         get {
440                                 return _propertyCount;
441                         }
442                 }
443         }
444 }