2009-08-14 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel.Channels / CommunicationObject.cs
1 //
2 // CommunicationObject.cs
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2005 Novell, Inc.  http://www.novell.com
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 using System;
29 using System.ServiceModel;
30 using System.Threading;
31
32 namespace System.ServiceModel.Channels
33 {
34         public abstract class CommunicationObject : ICommunicationObject
35         {
36                 object mutex;
37                 CommunicationState state = CommunicationState.Created;
38                 TimeSpan default_open_timeout = TimeSpan.FromMinutes (1), default_close_timeout = TimeSpan.FromMinutes (1);
39                 bool aborted, on_closed_called;
40
41                 protected CommunicationObject ()
42                         : this (new object ())
43                 {
44                 }
45
46                 protected CommunicationObject (object mutex)
47                 {
48                         this.mutex = mutex;
49                 }
50
51                 #region Events
52
53                 public event EventHandler Closed;
54
55                 public event EventHandler Closing;
56
57                 public event EventHandler Faulted;
58
59                 public event EventHandler Opened;
60
61                 public event EventHandler Opening;
62
63                 #endregion
64
65                 #region Properties
66
67                 public CommunicationState State {
68                         get { return state; }
69                 }
70
71                 protected bool IsDisposed {
72                         get { return state == CommunicationState.Closed; }
73                 }
74
75                 protected object ThisLock {
76                         get { return mutex; }
77                 }
78
79                 protected internal abstract TimeSpan DefaultCloseTimeout { get; }
80
81                 protected internal abstract TimeSpan DefaultOpenTimeout { get; }
82
83                 #endregion
84
85                 #region Methods
86
87                 public void Abort ()
88                 {
89                         if (State != CommunicationState.Closed) {
90                                 OnAbort ();
91                                 ProcessClosed ();
92                         }
93                 }
94
95                 [MonoTODO]
96                 protected void Fault ()
97                 {
98                         state = CommunicationState.Faulted;
99                         OnFaulted ();
100                 }
101
102                 public IAsyncResult BeginClose (AsyncCallback callback,
103                         object state)
104                 {
105                         return BeginClose (default_close_timeout, callback, state);
106                 }
107
108                 public IAsyncResult BeginClose (TimeSpan timeout,
109                         AsyncCallback callback, object state)
110                 {
111                         if (State == CommunicationState.Created)
112                                 return new EventHandler (delegate { Abort (); }).BeginInvoke (null, null, callback, state);
113                         ProcessClosing ();
114                         return OnBeginClose (timeout, callback, state);
115                 }
116
117                 public IAsyncResult BeginOpen (AsyncCallback callback,
118                         object state)
119                 {
120                         return BeginOpen (default_open_timeout, callback, state);
121                 }
122
123                 public IAsyncResult BeginOpen (TimeSpan timeout,
124                         AsyncCallback callback, object state)
125                 {
126                         ProcessOpening ();
127                         return OnBeginOpen (timeout, callback, state);
128                 }
129
130                 public void Close ()
131                 {
132                         Close (default_close_timeout);
133                 }
134
135                 public void Close (TimeSpan timeout)
136                 {
137                         if (State == CommunicationState.Created)
138                                 Abort ();
139                         else {
140                                 ProcessClosing ();
141                                 OnClose (timeout);
142                                 ProcessClosed ();
143                         }
144                 }
145
146                 public void EndClose (IAsyncResult result)
147                 {
148                         if (State == CommunicationState.Created || State == CommunicationState.Closed) {
149                                 if (!result.IsCompleted)
150                                         result.AsyncWaitHandle.WaitOne ();
151                         } else {
152                                 OnEndClose (result);
153                                 ProcessClosed ();
154                         }
155                 }
156
157                 public void EndOpen (IAsyncResult result)
158                 {
159                         OnEndOpen (result);
160                         ProcessOpened ();
161                 }
162
163                 public void Open ()
164                 {
165                         Open (default_open_timeout);
166                 }
167
168                 public void Open (TimeSpan timeout)
169                 {
170                         ProcessOpening ();
171                         OnOpen (timeout);
172                         ProcessOpened ();
173                 }
174
175                 protected abstract void OnAbort ();
176
177                 protected abstract IAsyncResult OnBeginClose (TimeSpan timeout,
178                         AsyncCallback callback, object state);
179
180                 protected abstract IAsyncResult OnBeginOpen (TimeSpan timeout,
181                         AsyncCallback callback, object state);
182
183                 protected abstract void OnClose (TimeSpan timeout);
184
185                 void ProcessClosing ()
186                 {
187                         if (State == CommunicationState.Faulted)
188                                 throw new CommunicationObjectFaultedException ();
189                         state = CommunicationState.Closing;
190                         OnClosing ();
191                 }
192
193                 protected virtual void OnClosing ()
194                 {
195                         // This means, if this method is overriden, then
196                         // Opening event is surpressed.
197                         if (Closing != null)
198                                 Closing (this, new EventArgs ());
199                 }
200
201                 void ProcessClosed ()
202                 {
203                         state = CommunicationState.Closed;
204                         on_closed_called = false;
205                         OnClosed ();
206                         if (!on_closed_called)
207                                 throw new InvalidOperationException ("OnClosed method is implemented but it did not call its base OnClosed method");
208                 }
209
210                 protected virtual void OnClosed ()
211                 {
212                         // This means, if this method is overriden, then
213                         // Closed event is surpressed.
214                         if (Closed != null)
215                                 Closed (this, new EventArgs ());
216                         on_closed_called = true;
217                 }
218
219                 protected abstract void OnEndClose (IAsyncResult result);
220
221                 protected abstract void OnEndOpen (IAsyncResult result);
222
223                 [MonoTODO]
224                 protected virtual void OnFaulted ()
225                 {
226                         // This means, if this method is overriden, then
227                         // Opened event is surpressed.
228                         if (Faulted != null)
229                                 Faulted (this, new EventArgs ());
230                 }
231
232                 protected abstract void OnOpen (TimeSpan timeout);
233
234                 void ProcessOpened ()
235                 {
236                         state = CommunicationState.Opened;
237                         OnOpened ();
238                 }
239
240                 protected virtual void OnOpened ()
241                 {
242                         // This means, if this method is overriden, then
243                         // Opened event is surpressed.
244                         if (Opened != null)
245                                 Opened (this, new EventArgs ());
246                 }
247
248                 void ProcessOpening ()
249                 {
250                         ThrowIfDisposedOrImmutable ();
251                         state = CommunicationState.Opening;
252                         OnOpening ();
253                 }
254
255                 protected virtual void OnOpening ()
256                 {
257                         // This means, if this method is overriden, then
258                         // Opening event is surpressed.
259                         if (Opening != null)
260                                 Opening (this, new EventArgs ());
261                 }
262
263                 protected void ThrowIfDisposed ()
264                 {
265                         if (IsDisposed)
266                                 throw new ObjectDisposedException (String.Format ("This communication object {0} is already disposed.", GetCommunicationObjectType ()));
267                 }
268
269                 protected void ThrowIfDisposedOrNotOpen ()
270                 {
271                         ThrowIfDisposed ();
272                         if (State == CommunicationState.Faulted)
273                                 throw new CommunicationObjectFaultedException ();
274                         if (State != CommunicationState.Opened)
275                                 throw new InvalidOperationException (String.Format ("The communication object {0} must be at opened state.", GetCommunicationObjectType ()));
276                 }
277
278                 protected void ThrowIfDisposedOrImmutable ()
279                 {
280                         ThrowIfDisposed ();
281                         // hmm, according to msdn, Closing is OK here.
282                         switch (State) {
283                         case CommunicationState.Faulted:
284                                 throw new CommunicationObjectFaultedException ();
285                         case CommunicationState.Opening:
286                         case CommunicationState.Opened:
287                                 throw new InvalidOperationException (String.Format ("The communication object {0} is not at created state.", GetType ()));
288                         }
289                 }
290
291                 protected virtual Type GetCommunicationObjectType ()
292                 {
293                         return GetType ();
294                 }
295
296                 #endregion
297
298
299                 class SimpleAsyncResult : IAsyncResult
300                 {
301                         CommunicationState comm_state;
302                         object async_state;
303
304                         public SimpleAsyncResult (
305                                 CommunicationState communicationState,
306                                 TimeSpan timeout, AsyncCallback callback,
307                                 object asyncState)
308                         {
309                                 comm_state = communicationState;
310                                 async_state = asyncState;
311                         }
312
313                         public object AsyncState {
314                                 get { return async_state; }
315                         }
316
317                         // FIXME: implement
318                         public WaitHandle AsyncWaitHandle {
319                                 get { throw new NotImplementedException (); }
320                         }
321
322                         // FIXME: implement
323                         public bool CompletedSynchronously {
324                                 get { throw new NotImplementedException (); }
325                         }
326
327                         // FIXME: implement
328                         public bool IsCompleted {
329                                 get { throw new NotImplementedException (); }
330                         }
331                 }
332         }
333 }