a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
364 lines
10 KiB
C#
364 lines
10 KiB
C#
//
|
|
// 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;
|
|
if (Opened != null)
|
|
Opened (this, new EventArgs ());
|
|
}
|
|
|
|
void ProcessOpening ()
|
|
{
|
|
lock (ThisLock) {
|
|
ThrowIfDisposedOrImmutable ();
|
|
OnOpening ();
|
|
if (state != CommunicationState.Opening) {
|
|
state = CommunicationState.Faulted;
|
|
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));
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual void OnOpening ()
|
|
{
|
|
state = CommunicationState.Opening;
|
|
// This means, if this method is overriden, then
|
|
// Opening event is surpressed.
|
|
if (Opening != null)
|
|
Opening (this, new EventArgs ());
|
|
}
|
|
|
|
protected void ThrowIfDisposed ()
|
|
{
|
|
if (IsDisposed)
|
|
throw new ObjectDisposedException (String.Format ("This communication object {0} is already disposed.", GetCommunicationObjectType ()));
|
|
}
|
|
|
|
protected void ThrowIfDisposedOrNotOpen ()
|
|
{
|
|
ThrowIfDisposed ();
|
|
if (State == CommunicationState.Faulted)
|
|
throw new CommunicationObjectFaultedException ();
|
|
if (State != CommunicationState.Opened)
|
|
throw new InvalidOperationException (String.Format ("The communication object {0} must be at opened state.", GetCommunicationObjectType ()));
|
|
}
|
|
|
|
protected void ThrowIfDisposedOrImmutable ()
|
|
{
|
|
ThrowIfDisposed ();
|
|
// hmm, according to msdn, Closing is OK here.
|
|
switch (State) {
|
|
case CommunicationState.Faulted:
|
|
throw new CommunicationObjectFaultedException ();
|
|
case CommunicationState.Opening:
|
|
case CommunicationState.Opened:
|
|
throw new InvalidOperationException (String.Format ("The communication object {0} is not at created state but at {1} state.", GetType (), State));
|
|
}
|
|
}
|
|
|
|
protected virtual Type GetCommunicationObjectType ()
|
|
{
|
|
return GetType ();
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
class SimpleAsyncResult : IAsyncResult
|
|
{
|
|
CommunicationState comm_state;
|
|
object async_state;
|
|
|
|
public SimpleAsyncResult (
|
|
CommunicationState communicationState,
|
|
TimeSpan timeout, AsyncCallback callback,
|
|
object asyncState)
|
|
{
|
|
comm_state = communicationState;
|
|
async_state = asyncState;
|
|
}
|
|
|
|
public object AsyncState {
|
|
get { return async_state; }
|
|
}
|
|
|
|
// FIXME: implement
|
|
public WaitHandle AsyncWaitHandle {
|
|
get { throw new NotImplementedException (); }
|
|
}
|
|
|
|
// FIXME: implement
|
|
public bool CompletedSynchronously {
|
|
get { throw new NotImplementedException (); }
|
|
}
|
|
|
|
// FIXME: implement
|
|
public bool IsCompleted {
|
|
get { throw new NotImplementedException (); }
|
|
}
|
|
}
|
|
}
|
|
}
|