2004-09-11 Ben Maurer <bmaurer@users.sourceforge.net>
[mono-project.git] / mcs / class / corlib / System.Runtime.Remoting.Messaging / CADMessages.cs
blobee14562358f171e00f4a9d2f1aa2478198d670b4
1 //
2 // System.Runtime.Remoting.Messaging.CADMessages.cs
3 //
4 // Author:
5 // Patrik Torstensson
6 //
7 // (C) Patrik Torstensson
8 //
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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.
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;
42 namespace System.Runtime.Remoting.Messaging {
44 internal class CADArgHolder {
45 public int index;
47 public CADArgHolder (int i) {
48 index = i;
52 internal class CADObjRef {
53 ObjRef objref;
54 public int SourceDomain;
56 public CADObjRef (ObjRef o, int sourceDomain) {
57 objref = o;
58 SourceDomain = sourceDomain;
61 public string TypeName {
62 get { return objref.TypeInfo.TypeName; }
65 public string URI {
66 get { return objref.URI; }
70 internal class CADMessageBase {
72 protected object [] _args;
73 protected byte [] _serializedArgs = null;
74 protected int _propertyCount = 0;
75 protected CADArgHolder _callContext;
77 // Helper to marshal properties
78 internal static int MarshalProperties (IDictionary dict, ref ArrayList args) {
79 IDictionary serDict = dict;
80 int count = 0;
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++;
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++;
106 return count;
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;
116 // We can ignore marshalling for string and primitive types
117 private static bool IsPossibleToIgnoreMarshal (object obj) {
119 Type objType = obj.GetType();
120 if (objType.IsPrimitive || objType == typeof(void))
121 return true;
123 if (objType.IsArray && objType.GetElementType().IsPrimitive && ((Array)obj).Rank == 1)
124 return true;
126 if (obj is string || obj is DateTime || obj is TimeSpan)
127 return true;
129 return false;
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;
138 if (IsPossibleToIgnoreMarshal (arg))
139 return arg;
141 MarshalByRefObject mbr = arg as MarshalByRefObject;
142 if (null != mbr)
144 if (RemotingServices.IsTransparentProxy(mbr)) {
145 // We don't deal with this case yet
147 else {
148 ObjRef objRef = RemotingServices.Marshal(mbr);
149 return new CADObjRef(objRef, System.Threading.Thread.GetDomainID());
153 if (null == args)
154 args = new ArrayList();
156 args.Add (arg);
158 // return position that the arg exists in the serialized list
159 return new CADArgHolder(args.Count - 1);
162 protected object UnmarshalArgument (object arg, ArrayList args) {
163 if (arg == null) return null;
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];
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;
177 ChannelInfo cinfo = new ChannelInfo (new CrossAppDomainData (domid));
178 ObjRef localRef = new ObjRef (typeName, uri, cinfo);
179 return RemotingServices.Unmarshal (localRef);
182 if (arg is Array)
184 Array argb = (Array)arg;
185 Array argn;
187 // We can't use Array.CreateInstance (arg.GetType().GetElementType()) because
188 // GetElementType() returns a type from the source domain.
190 switch (Type.GetTypeCode (arg.GetType().GetElementType()))
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 ();
208 argb.CopyTo (argn, 0);
209 return argn;
212 switch (Type.GetTypeCode (arg.GetType()))
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;
234 throw new NotSupportedException ("Parameter of type " + arg.GetType () + " cannot be unmarshalled");
237 internal object [] MarshalArguments (object [] arguments, ref ArrayList args) {
238 object [] marshalledArgs = new object [arguments.Length];
240 int total = arguments.Length;
241 for (int i = 0; i < total; i++)
242 marshalledArgs [i] = MarshalArgument (arguments [i], ref args);
244 return marshalledArgs;
247 internal object [] UnmarshalArguments (object [] arguments, ArrayList args) {
248 object [] unmarshalledArgs = new object [arguments.Length];
250 int total = arguments.Length;
251 for (int i = 0; i < total; i++)
252 unmarshalledArgs [i] = UnmarshalArgument (arguments [i], args);
254 return unmarshalledArgs;
257 protected void SaveLogicalCallContext (IMethodMessage msg, ref ArrayList serializeList)
259 if (msg.LogicalCallContext != null && msg.LogicalCallContext.HasInfo)
261 if (serializeList == null)
262 serializeList = new ArrayList();
264 _callContext = new CADArgHolder (serializeList.Count);
265 serializeList.Add (msg.LogicalCallContext);
269 internal LogicalCallContext GetLogicalCallContext (ArrayList args)
271 if (null == _callContext)
272 return null;
274 return (LogicalCallContext) args [_callContext.index];
278 // Used when passing a IMethodCallMessage between appdomains
279 internal class CADMethodCallMessage : CADMessageBase {
280 string _uri;
282 internal RuntimeMethodHandle MethodHandle;
284 internal string Uri {
285 get {
286 return _uri;
290 static internal CADMethodCallMessage Create (IMessage callMsg) {
291 IMethodCallMessage msg = callMsg as IMethodCallMessage;
292 if (null == msg)
293 return null;
295 return new CADMethodCallMessage (msg);
298 internal CADMethodCallMessage (IMethodCallMessage callMsg) {
299 _uri = callMsg.Uri;
300 MethodHandle = callMsg.MethodBase.MethodHandle;
302 ArrayList serializeList = null;
304 _propertyCount = MarshalProperties (callMsg.Properties, ref serializeList);
306 _args = MarshalArguments ( callMsg.Args, ref serializeList);
308 // Save callcontext
309 SaveLogicalCallContext (callMsg, ref serializeList);
311 // Serialize message data if needed
313 if (null != serializeList) {
314 MemoryStream stm = CADSerializer.SerializeObject (serializeList.ToArray());
315 _serializedArgs = stm.GetBuffer();
319 internal ArrayList GetArguments () {
320 ArrayList ret = null;
322 if (null != _serializedArgs) {
323 object[] oret = (object[]) CADSerializer.DeserializeObject (new MemoryStream (_serializedArgs));
324 ret = new ArrayList (oret);
325 _serializedArgs = null;
328 return ret;
331 internal object [] GetArgs (ArrayList args) {
332 return UnmarshalArguments (_args, args);
335 internal int PropertiesCount {
336 get {
337 return _propertyCount;
342 // Used when passing a IMethodReturnMessage between appdomains
343 internal class CADMethodReturnMessage : CADMessageBase {
344 object _returnValue;
345 CADArgHolder _exception = null;
347 static internal CADMethodReturnMessage Create (IMessage callMsg) {
348 IMethodReturnMessage msg = callMsg as IMethodReturnMessage;
349 if (null == msg)
350 return null;
352 return new CADMethodReturnMessage (msg);
355 internal CADMethodReturnMessage(IMethodReturnMessage retMsg) {
356 ArrayList serializeList = null;
358 _propertyCount = MarshalProperties (retMsg.Properties, ref serializeList);
360 _returnValue = MarshalArgument ( retMsg.ReturnValue, ref serializeList);
361 _args = MarshalArguments ( retMsg.Args, ref serializeList);
363 if (null != retMsg.Exception) {
364 if (null == serializeList)
365 serializeList = new ArrayList();
367 _exception = new CADArgHolder (serializeList.Count);
368 serializeList.Add(retMsg.Exception);
371 // Save callcontext
372 SaveLogicalCallContext (retMsg, ref serializeList);
374 if (null != serializeList) {
375 MemoryStream stm = CADSerializer.SerializeObject (serializeList.ToArray());
376 _serializedArgs = stm.GetBuffer();
380 internal ArrayList GetArguments () {
381 ArrayList ret = null;
383 if (null != _serializedArgs) {
384 object[] oret = (object[]) CADSerializer.DeserializeObject (new MemoryStream (_serializedArgs));
385 ret = new ArrayList (oret);
386 _serializedArgs = null;
389 return ret;
392 internal object [] GetArgs (ArrayList args) {
393 return UnmarshalArguments (_args, args);
396 internal object GetReturnValue (ArrayList args) {
397 return UnmarshalArgument (_returnValue, args);
400 internal Exception GetException(ArrayList args) {
401 if (null == _exception)
402 return null;
404 return (Exception) args [_exception.index];
407 internal int PropertiesCount {
408 get {
409 return _propertyCount;