Merge pull request #1708 from alexanderkyte/always_use_imt
[mono.git] / mcs / class / corlib / System.Runtime.Remoting / ServerIdentity.cs
1 //
2 // System.Runtime.Remoting.Identity.cs
3 //
4 // Author: Lluis Sanchez Gual (lluis@ideary.com)
5 //
6 // (C) 2002, Lluis Sanchez Gual
7 //
8
9 //
10 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System;
33 using System.Runtime.Remoting.Messaging;
34 using System.Runtime.Remoting.Contexts;
35 using System.Runtime.Remoting.Lifetime;
36 using System.Runtime.Remoting.Proxies;
37 using System.Runtime.Remoting.Services;
38
39 namespace System.Runtime.Remoting
40 {
41         internal abstract class ServerIdentity : Identity
42         {
43                 protected Type _objectType;
44
45                 protected MarshalByRefObject _serverObject;
46
47                 // Message sink used in the server to dispatch a message
48                 // to the server object
49                 protected IMessageSink _serverSink = null;
50
51                 protected Context _context;
52                 protected Lease _lease;
53
54                 public ServerIdentity (string objectUri, Context context, Type objectType): base (objectUri)
55                 {
56                         _objectType = objectType;
57                         _context = context;
58                 }
59
60                 public Type ObjectType
61                 {
62                         get { return _objectType; }
63                 }
64
65                 public void StartTrackingLifetime (ILease lease)
66                 {
67                         // Adds this identity to the LeaseManager. 
68                         // _serverObject must be set.
69
70                         if (lease != null && lease.CurrentState == LeaseState.Null) lease = null;
71
72                         if (lease != null) 
73                         {
74                                 if (! (lease is Lease)) lease = new Lease();  // This seems to be MS behavior
75                                 _lease = (Lease) lease;
76                                 LifetimeServices.TrackLifetime (this);
77                         }
78                 }
79
80                 public virtual void OnLifetimeExpired()
81                 {
82                         DisposeServerObject();
83                 }
84
85                 public override ObjRef CreateObjRef (Type requestedType)
86                 {
87                         if (_objRef != null)
88                         {
89                                 // Just update channel info. It may have changed.
90                                 _objRef.UpdateChannelInfo();
91                                 return _objRef;
92                         }
93
94                         if (requestedType == null) requestedType = _objectType;
95                         _objRef = new ObjRef ();
96                         _objRef.TypeInfo = new TypeInfo(requestedType);
97                         _objRef.URI = _objectUri;
98
99                         if (_envoySink != null && !(_envoySink is EnvoyTerminatorSink))
100                                 _objRef.EnvoyInfo = new EnvoyInfo (_envoySink);
101
102                         return _objRef;
103                 }
104
105                 public void AttachServerObject (MarshalByRefObject serverObject, Context context)
106                 {
107                         DisposeServerObject();
108
109                         _context = context;
110                         _serverObject = serverObject;
111                         
112                         if (RemotingServices.IsTransparentProxy (serverObject))
113                         {
114                                 RealProxy rp = RemotingServices.GetRealProxy (serverObject);
115                                 if (rp.ObjectIdentity == null)
116                                         rp.ObjectIdentity = this;
117                         }
118                         else
119                         {
120                                 if (_objectType.IsContextful)
121                                         _envoySink = context.CreateEnvoySink (serverObject);
122         
123                                 _serverObject.ObjectIdentity = this;
124                         }
125                 }
126
127                 public Lease Lease
128                 {
129                         get { return _lease; }
130                 }
131
132                 public Context Context
133                 {
134                         get { return _context; }
135                         set { _context = value; }
136                 }
137
138                 public abstract IMessage SyncObjectProcessMessage (IMessage msg);
139                 public abstract IMessageCtrl AsyncObjectProcessMessage (IMessage msg, IMessageSink replySink);
140
141                 protected void DisposeServerObject()
142                 {
143                         // Detach identity from server object to avoid problems if the
144                         // object is marshalled again.
145                         
146                         if (_serverObject != null) {
147                                 MarshalByRefObject obj = _serverObject;
148                                 _serverObject.ObjectIdentity = null;
149                                 _serverObject = null;
150                                 _serverSink = null;
151                                 TrackingServices.NotifyDisconnectedObject (obj);
152                         }
153                 }
154         }
155
156         internal class ClientActivatedIdentity : ServerIdentity
157         {
158                 MarshalByRefObject _targetThis;
159                 
160                 public ClientActivatedIdentity (string objectUri, Type objectType): base (objectUri, null, objectType)
161                 {
162                 }
163         
164                 public MarshalByRefObject GetServerObject ()
165                 {
166                         return _serverObject;
167                 }
168
169                 public MarshalByRefObject GetClientProxy ()
170                 {
171                         return _targetThis;
172                 }
173                 
174                 public void SetClientProxy (MarshalByRefObject obj)
175                 {
176                         _targetThis = obj;
177                 }
178
179                 public override void OnLifetimeExpired()
180                 {
181                         base.OnLifetimeExpired();
182                         RemotingServices.DisposeIdentity (this);
183                 }
184
185                 public override IMessage SyncObjectProcessMessage (IMessage msg)
186                 {
187                         if (_serverSink == null) {
188                                 bool useProxy = _targetThis != null;
189                                 _serverSink = _context.CreateServerObjectSinkChain ((useProxy ? _targetThis : _serverObject), useProxy);
190                         }
191                         return _serverSink.SyncProcessMessage (msg);
192                 }
193
194                 public override IMessageCtrl AsyncObjectProcessMessage (IMessage msg, IMessageSink replySink)
195                 {
196                         if (_serverSink == null) {
197                                 bool useProxy = _targetThis != null;
198                                 _serverSink = _context.CreateServerObjectSinkChain ((useProxy ? _targetThis : _serverObject), useProxy);
199                         }
200                         return _serverSink.AsyncProcessMessage (msg, replySink);
201                 }       
202         }
203
204         internal class SingletonIdentity : ServerIdentity
205         {
206                 public SingletonIdentity (string objectUri, Context context, Type objectType): base (objectUri, context, objectType)
207                 {
208                 }
209
210                 public MarshalByRefObject GetServerObject ()
211                 {
212                         if (_serverObject != null) return _serverObject;
213
214                         lock (this) 
215                         {
216                                 if (_serverObject == null) {
217                                         MarshalByRefObject server = (MarshalByRefObject) Activator.CreateInstance (_objectType, true);
218                                         AttachServerObject (server, Context.DefaultContext);
219                                         StartTrackingLifetime ((ILease)server.InitializeLifetimeService ());
220                                 }
221                         }
222                         return _serverObject;
223                 }
224
225                 public override IMessage SyncObjectProcessMessage (IMessage msg)
226                 {
227                         MarshalByRefObject obj = GetServerObject ();
228                         if (_serverSink == null) _serverSink = _context.CreateServerObjectSinkChain (obj, false);
229                         return _serverSink.SyncProcessMessage (msg);
230                 }
231
232                 public override IMessageCtrl AsyncObjectProcessMessage (IMessage msg, IMessageSink replySink)
233                 {
234                         MarshalByRefObject obj = GetServerObject ();
235                         if (_serverSink == null) _serverSink = _context.CreateServerObjectSinkChain (obj, false);
236                         return _serverSink.AsyncProcessMessage (msg, replySink);
237                 }       
238         }
239
240         internal class SingleCallIdentity : ServerIdentity
241         {
242                 public SingleCallIdentity (string objectUri, Context context, Type objectType): base (objectUri, context, objectType)
243                 {
244                 }
245
246                 public override IMessage SyncObjectProcessMessage (IMessage msg)
247                 {
248                         // SingleCallIdentity creates and disposes an instance in each call
249
250                         MarshalByRefObject obj = (MarshalByRefObject)Activator.CreateInstance (_objectType, true);
251                         if (obj.ObjectIdentity == null) obj.ObjectIdentity = this;
252                         IMessageSink serverSink = _context.CreateServerObjectSinkChain (obj, false);
253                         IMessage result = serverSink.SyncProcessMessage (msg);
254                         if (obj is IDisposable) ((IDisposable)obj).Dispose();
255                         return result;
256                 }
257
258                 public override IMessageCtrl AsyncObjectProcessMessage (IMessage msg, IMessageSink replySink)
259                 {
260                         MarshalByRefObject obj = (MarshalByRefObject)Activator.CreateInstance (_objectType, true);
261                         IMessageSink serverSink = _context.CreateServerObjectSinkChain (obj, false);
262                         if (obj is IDisposable) replySink = new DisposerReplySink(replySink, ((IDisposable)obj));
263                         return serverSink.AsyncProcessMessage (msg, replySink);
264                 }       
265         }
266
267         internal class DisposerReplySink : IMessageSink
268         {
269                 IMessageSink _next;
270                 IDisposable _disposable;
271
272                 public DisposerReplySink (IMessageSink next, IDisposable disposable)
273                 {
274                         _next = next;
275                         _disposable = disposable;
276                 }
277
278                 public IMessage SyncProcessMessage (IMessage msg)
279                 {
280                         _disposable.Dispose();
281                         return _next.SyncProcessMessage (msg);
282                 }
283
284                 public IMessageCtrl AsyncProcessMessage (IMessage msg, IMessageSink replySink)
285                 {
286                         throw new NotSupportedException();
287                 }
288
289                 public IMessageSink NextSink
290                 {
291                         get { return _next; }
292                 }
293         }
294 }