2010-06-03 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System.ServiceModel / System.ServiceModel.Channels / CommunicationObject.cs
blob88a186400749aa93d9e3f1ef62284cd589948ba0
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.
28 using System;
29 using System.Reflection;
30 using System.ServiceModel;
31 using System.Threading;
33 namespace System.ServiceModel.Channels
35 public abstract class CommunicationObject : ICommunicationObject
37 object mutex;
38 CommunicationState state = CommunicationState.Created;
39 TimeSpan default_open_timeout = TimeSpan.FromMinutes (1), default_close_timeout = TimeSpan.FromMinutes (1);
40 bool aborted;
42 protected CommunicationObject ()
43 : this (new object ())
47 protected CommunicationObject (object mutex)
49 this.mutex = mutex;
52 #region Events
54 public event EventHandler Closed;
56 public event EventHandler Closing;
58 public event EventHandler Faulted;
60 public event EventHandler Opened;
62 public event EventHandler Opening;
64 #endregion
66 #region Properties
68 public CommunicationState State {
69 get { return state; }
72 protected bool IsDisposed {
73 get { return state == CommunicationState.Closed; }
76 protected object ThisLock {
77 get { return mutex; }
80 protected internal abstract TimeSpan DefaultCloseTimeout { get; }
82 protected internal abstract TimeSpan DefaultOpenTimeout { get; }
84 #endregion
86 #region Methods
88 public void Abort ()
90 if (State != CommunicationState.Closed) {
91 OnAbort ();
92 ProcessClosed ();
96 protected void Fault ()
98 ProcessFaulted ();
101 public IAsyncResult BeginClose (AsyncCallback callback,
102 object state)
104 return BeginClose (default_close_timeout, callback, state);
107 public IAsyncResult BeginClose (TimeSpan timeout,
108 AsyncCallback callback, object state)
110 if (State == CommunicationState.Created)
111 return new EventHandler (delegate { Abort (); }).BeginInvoke (null, null, callback, state);
112 ProcessClosing ();
113 return OnBeginClose (timeout, callback, state);
116 public IAsyncResult BeginOpen (AsyncCallback callback,
117 object state)
119 return BeginOpen (default_open_timeout, callback, state);
122 public IAsyncResult BeginOpen (TimeSpan timeout,
123 AsyncCallback callback, object state)
125 ProcessOpening ();
126 return OnBeginOpen (timeout, callback, state);
129 public void Close ()
131 Close (default_close_timeout);
134 public void Close (TimeSpan timeout)
136 if (State == CommunicationState.Created)
137 Abort ();
138 else {
139 ProcessClosing ();
140 OnClose (timeout);
141 ProcessClosed ();
145 public void EndClose (IAsyncResult result)
147 if (State == CommunicationState.Created || State == CommunicationState.Closed) {
148 if (!result.IsCompleted)
149 result.AsyncWaitHandle.WaitOne ();
150 } else {
151 OnEndClose (result);
152 ProcessClosed ();
156 public void EndOpen (IAsyncResult result)
158 OnEndOpen (result);
159 ProcessOpened ();
162 public void Open ()
164 Open (default_open_timeout);
167 public void Open (TimeSpan timeout)
169 ProcessOpening ();
170 OnOpen (timeout);
171 ProcessOpened ();
174 protected abstract void OnAbort ();
176 protected abstract IAsyncResult OnBeginClose (TimeSpan timeout,
177 AsyncCallback callback, object state);
179 protected abstract IAsyncResult OnBeginOpen (TimeSpan timeout,
180 AsyncCallback callback, object state);
182 protected abstract void OnClose (TimeSpan timeout);
184 void ProcessClosing ()
186 lock (ThisLock) {
187 if (State == CommunicationState.Faulted)
188 throw new CommunicationObjectFaultedException ();
189 OnClosing ();
190 if (state != CommunicationState.Closing) {
191 state = CommunicationState.Faulted;
192 throw new InvalidOperationException (String.Format ("Communication object {0} has an overriden OnClosing method that does not call base OnClosing method (declared in {1} type).", this.GetType (), GetType ().GetMethod ("OnClosing", BindingFlags.NonPublic | BindingFlags.Instance).DeclaringType));
197 protected virtual void OnClosing ()
199 state = CommunicationState.Closing;
200 // This means, if this method is overriden, then
201 // Opening event is surpressed.
202 if (Closing != null)
203 Closing (this, new EventArgs ());
206 void ProcessClosed ()
208 lock (ThisLock) {
209 OnClosed ();
210 if (state != CommunicationState.Closed) {
211 state = CommunicationState.Faulted;
212 throw new InvalidOperationException (String.Format ("Communication object {0} has an overriden OnClosed method that does not call base OnClosed method (declared in {1} type).", this.GetType (), GetType ().GetMethod ("OnClosed", BindingFlags.NonPublic | BindingFlags.Instance).DeclaringType));
217 protected virtual void OnClosed ()
219 state = CommunicationState.Closed;
220 // This means, if this method is overriden, then
221 // Closed event is surpressed.
222 if (Closed != null)
223 Closed (this, new EventArgs ());
226 protected abstract void OnEndClose (IAsyncResult result);
228 protected abstract void OnEndOpen (IAsyncResult result);
230 void ProcessFaulted ()
232 lock (ThisLock) {
233 if (State == CommunicationState.Faulted)
234 throw new CommunicationObjectFaultedException ();
235 OnFaulted ();
236 if (state != CommunicationState.Faulted) {
237 state = CommunicationState.Faulted; // FIXME: am not sure if this makes sense ...
238 throw new InvalidOperationException (String.Format ("Communication object {0} has an overriden OnFaulted method that does not call base OnFaulted method (declared in {1} type).", this.GetType (), GetType ().GetMethod ("OnFaulted", BindingFlags.NonPublic | BindingFlags.Instance).DeclaringType));
243 protected virtual void OnFaulted ()
245 state = CommunicationState.Faulted;
246 // This means, if this method is overriden, then
247 // Faulted event is surpressed.
248 if (Faulted != null)
249 Faulted (this, new EventArgs ());
252 protected abstract void OnOpen (TimeSpan timeout);
254 void ProcessOpened ()
256 lock (ThisLock) {
257 OnOpened ();
258 if (state != CommunicationState.Opened) {
259 state = CommunicationState.Faulted;
260 throw new InvalidOperationException (String.Format ("Communication object {0} has an overriden OnOpened method that does not call base OnOpened method (declared in {1} type).", this.GetType (), GetType ().GetMethod ("OnOpened", BindingFlags.NonPublic | BindingFlags.Instance).DeclaringType));
265 protected virtual void OnOpened ()
267 state = CommunicationState.Opened;
268 if (Opened != null)
269 Opened (this, new EventArgs ());
272 void ProcessOpening ()
274 lock (ThisLock) {
275 ThrowIfDisposedOrImmutable ();
276 OnOpening ();
277 if (state != CommunicationState.Opening) {
278 state = CommunicationState.Faulted;
279 throw new InvalidOperationException (String.Format ("Communication object {0} has an overriden OnOpening method that does not call base OnOpening method (declared in {1} type).", this.GetType (), GetType ().GetMethod ("OnOpening", BindingFlags.NonPublic | BindingFlags.Instance).DeclaringType));
284 protected virtual void OnOpening ()
286 state = CommunicationState.Opening;
287 // This means, if this method is overriden, then
288 // Opening event is surpressed.
289 if (Opening != null)
290 Opening (this, new EventArgs ());
293 protected void ThrowIfDisposed ()
295 if (IsDisposed)
296 throw new ObjectDisposedException (String.Format ("This communication object {0} is already disposed.", GetCommunicationObjectType ()));
299 protected void ThrowIfDisposedOrNotOpen ()
301 ThrowIfDisposed ();
302 if (State == CommunicationState.Faulted)
303 throw new CommunicationObjectFaultedException ();
304 if (State != CommunicationState.Opened)
305 throw new InvalidOperationException (String.Format ("The communication object {0} must be at opened state.", GetCommunicationObjectType ()));
308 protected void ThrowIfDisposedOrImmutable ()
310 ThrowIfDisposed ();
311 // hmm, according to msdn, Closing is OK here.
312 switch (State) {
313 case CommunicationState.Faulted:
314 throw new CommunicationObjectFaultedException ();
315 case CommunicationState.Opening:
316 case CommunicationState.Opened:
317 throw new InvalidOperationException (String.Format ("The communication object {0} is not at created state but at {1} state.", GetType (), State));
321 protected virtual Type GetCommunicationObjectType ()
323 return GetType ();
326 #endregion
329 class SimpleAsyncResult : IAsyncResult
331 CommunicationState comm_state;
332 object async_state;
334 public SimpleAsyncResult (
335 CommunicationState communicationState,
336 TimeSpan timeout, AsyncCallback callback,
337 object asyncState)
339 comm_state = communicationState;
340 async_state = asyncState;
343 public object AsyncState {
344 get { return async_state; }
347 // FIXME: implement
348 public WaitHandle AsyncWaitHandle {
349 get { throw new NotImplementedException (); }
352 // FIXME: implement
353 public bool CompletedSynchronously {
354 get { throw new NotImplementedException (); }
357 // FIXME: implement
358 public bool IsCompleted {
359 get { throw new NotImplementedException (); }