context: //
  // CommunicationObject.cs
  //
  // Author:
  //	Atsushi Enomoto <atsushi@ximian.com>
  //
  // Copyright (C) 2005 Novell, Inc.  http://www.novell.com
  //
  // Permission is hereby granted, free of charge, to any person obtaining
  // a copy of this software and associated documentation files (the
  // "Software"), to deal in the Software without restriction, including
  // without limitation the rights to use, copy, modify, merge, publish,
  // distribute, sublicense, and/or sell copies of the Software, and to
  // permit persons to whom the Software is furnished to do so, subject to
  // the following conditions:
  // 
  // The above copyright notice and this permission notice shall be
  // included in all copies or substantial portions of the Software.
  // 
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  //
  using System;
  using System.Reflection;
  using System.ServiceModel;
  using System.Threading;
  
  namespace System.ServiceModel.Channels
  {
  	public abstract class CommunicationObject : ICommunicationObject
  	{
  		object mutex;
  		CommunicationState state = CommunicationState.Created;
  		TimeSpan default_open_timeout = TimeSpan.FromMinutes (1), default_close_timeout = TimeSpan.FromMinutes (1);
  		bool aborted;
  
  		protected CommunicationObject ()
  			: this (new object ())
  		{
  		}
  
  		protected CommunicationObject (object mutex)
  		{
  			this.mutex = mutex;
  		}
  
  		#region Events
  
  		public event EventHandler Closed;
  
  		public event EventHandler Closing;
  
  		public event EventHandler Faulted;
  
  		public event EventHandler Opened;
  
  		public event EventHandler Opening;
  
  		#endregion
  
  		#region Properties
  
  		public CommunicationState State {
  			get { return state; }
  		}
  
  		protected bool IsDisposed {
  			get { return state == CommunicationState.Closed; }
  		}
  
  		protected object ThisLock {
  			get { return mutex; }
  		}
  
  		protected internal abstract TimeSpan DefaultCloseTimeout { get; }
  
  		protected internal abstract TimeSpan DefaultOpenTimeout { get; }
  
  		#endregion
  
  		#region Methods
  
  		public void Abort ()
  		{
  			if (State != CommunicationState.Closed) {
  				OnAbort ();
  				ProcessClosed ();
  			}
  		}
  
  		protected void Fault ()
  		{
  			ProcessFaulted ();
  		}
  
  		public IAsyncResult BeginClose (AsyncCallback callback,
  			object state)
  		{
  			return BeginClose (default_close_timeout, callback, state);
  		}
  
  		public IAsyncResult BeginClose (TimeSpan timeout,
  			AsyncCallback callback, object state)
  		{
  			if (State == CommunicationState.Created)
  				return new EventHandler (delegate { Abort (); }).BeginInvoke (null, null, callback, state);
  			ProcessClosing ();
  			return OnBeginClose (timeout, callback, state);
  		}
  
  		public IAsyncResult BeginOpen (AsyncCallback callback,
  			object state)
  		{
  			return BeginOpen (default_open_timeout, callback, state);
  		}
  
  		public IAsyncResult BeginOpen (TimeSpan timeout,
  			AsyncCallback callback, object state)
  		{
  			ProcessOpening ();
  			return OnBeginOpen (timeout, callback, state);
  		}
  
  		public void Close ()
  		{
  			Close (default_close_timeout);
  		}
  
  		public void Close (TimeSpan timeout)
  		{
  			if (State == CommunicationState.Created)
  				Abort ();
  			else {
  				ProcessClosing ();
  				OnClose (timeout);
  				ProcessClosed ();
  			}
  		}
  
  		public void EndClose (IAsyncResult result)
  		{
  			if (State == CommunicationState.Created || State == CommunicationState.Closed) {
  				if (!result.IsCompleted)
  					result.AsyncWaitHandle.WaitOne ();
  			} else {
  				OnEndClose (result);
  				ProcessClosed ();
  			}
  		}
  
  		public void EndOpen (IAsyncResult result)
  		{
  			OnEndOpen (result);
  			ProcessOpened ();
  		}
  
  		public void Open ()
  		{
  			Open (default_open_timeout);
  		}
  
  		public void Open (TimeSpan timeout)
  		{
  			ProcessOpening ();
  			OnOpen (timeout);
  			ProcessOpened ();
  		}
  
  		protected abstract void OnAbort ();
  
  		protected abstract IAsyncResult OnBeginClose (TimeSpan timeout,
  			AsyncCallback callback, object state);
  
  		protected abstract IAsyncResult OnBeginOpen (TimeSpan timeout,
  			AsyncCallback callback, object state);
  
  		protected abstract void OnClose (TimeSpan timeout);
  
  		void ProcessClosing ()
  		{
  			lock (ThisLock) {
  				if (State == CommunicationState.Faulted)
  					throw new CommunicationObjectFaultedException ();
  				OnClosing ();
  				if (state != CommunicationState.Closing) {
  					state = CommunicationState.Faulted;
  					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));
  				}
  			}
  		}
  
  		protected virtual void OnClosing ()
  		{
  			state = CommunicationState.Closing;
  			// This means, if this method is overriden, then
  			// Opening event is surpressed.
  			if (Closing != null)
  				Closing (this, new EventArgs ());
  		}
  
  		void ProcessClosed ()
  		{
  			lock (ThisLock) {
  				OnClosed ();
  				if (state != CommunicationState.Closed) {
  					state = CommunicationState.Faulted;
  					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));
  				}
  			}
  		}
  
  		protected virtual void OnClosed ()
  		{
  			state = CommunicationState.Closed;
  			// This means, if this method is overriden, then
  			// Closed event is surpressed.
  			if (Closed != null)
  				Closed (this, new EventArgs ());
  		}
  
  		protected abstract void OnEndClose (IAsyncResult result);
  
  		protected abstract void OnEndOpen (IAsyncResult result);
  
  		void ProcessFaulted ()
  		{
  			lock (ThisLock) {
  				if (State == CommunicationState.Faulted)
  					throw new CommunicationObjectFaultedException ();
  				OnFaulted ();
  				if (state != CommunicationState.Faulted) {
  					state = CommunicationState.Faulted; // FIXME: am not sure if this makes sense ...
  					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));
  				}
  			}
  		}
  
  		protected virtual void OnFaulted ()
  		{
  			state = CommunicationState.Faulted;
  			// This means, if this method is overriden, then
  			// Faulted event is surpressed.
  			if (Faulted != null)
  				Faulted (this, new EventArgs ());
  		}
  
  		protected abstract void OnOpen (TimeSpan timeout);
  
  		void ProcessOpened ()
  		{
  			lock (ThisLock) {
  				OnOpened ();
  				if (state != CommunicationState.Opened) {
  					state = CommunicationState.Faulted;
  					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));
  				}
  			}
  		}
  
  		protected virtual void OnOpened ()
  		{
  			state = CommunicationState.Opened;
  
gt: 			if (Opened != null)