//
// TransactionFlowBindingElement.cs
//
// Author:
// Atsushi Enomoto <atsushi@ximian.com>
//
// Copyright (C) 2006 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.Collections.Generic;
using System.ServiceModel.Description;
using System.ServiceModel.Security;
using System.ServiceModel.Channels;
using System.Transactions;
namespace System.ServiceModel.Channels{
public class TransactionFlowBindingElement : BindingElement
{
TransactionProtocol protocol;
// Funny, but since it uses OLE TX, Mono will never support this constructor.
[MonoTODO]
public TransactionFlowBindingElement ()
: this (TransactionProtocol.Default)
{
}
public TransactionFlowBindingElement (TransactionProtocol protocol)
{
this.protocol = protocol;
}
public TransactionProtocol TransactionProtocol {
get { return protocol; }
}
public override BindingElement Clone ()
{
return new TransactionFlowBindingElement (protocol);
}
[MonoTODO]
public override T GetProperty<T> (BindingContext context)
{
throw new NotImplementedException ();
}
public override bool CanBuildChannelFactory<TChannel> (BindingContext context)
{
return context.CanBuildInnerChannelFactory<TChannel> ();
}
[MonoTODO]
public override bool CanBuildChannelListener<TChannel> (BindingContext context)
{
return context.CanBuildInnerChannelListener<TChannel> ();
}
public override IChannelFactory<TChannel> BuildChannelFactory<TChannel> (BindingContext context)
{
if (protocol == null)
throw new InvalidOperationException ("Set transaction protocol in prior to build a channel factory.");
if (protocol == TransactionProtocol.Default)
throw new NotSupportedException ("Mono does not support DTC.");
if (!CanBuildChannelFactory<TChannel> (context.Clone ()))
throw new ArgumentException (String.Format ("The channel type '{0}' is not supported", typeof (TChannel)));
return new TransactionChannelFactory<TChannel> (context.BuildInnerChannelFactory<TChannel> (), protocol);
}
public override IChannelListener<TChannel> BuildChannelListener<TChannel> (BindingContext context)
{
if (protocol == null)
throw new InvalidOperationException ("Set transaction protocol in prior to build a channel listener.");
if (protocol == TransactionProtocol.Default)
throw new NotSupportedException ("Mono does not support DTC.");
if (!CanBuildChannelListener<TChannel> (context.Clone ()))
throw new ArgumentException (String.Format ("The channel type '{0}' is not supported", typeof (TChannel)));
return new TransactionChannelListener<TChannel> (
context.BuildInnerChannelListener<TChannel> (),
protocol);
}
}
internal class TransactionChannelFactory<TChannel> : ChannelFactoryBase<TChannel>
{
IChannelFactory<TChannel> inner_factory;
TransactionScope txscope;
TransactionProtocol protocol;
public TransactionChannelFactory (IChannelFactory<TChannel> innerFactory, TransactionProtocol protocol)
{
this.inner_factory = innerFactory;
this.protocol = protocol;
}
void ProcessOpen ()
{
CommittableTransaction tx = new CommittableTransaction ();
txscope = new TransactionScope (tx);
}
protected override void OnOpen (TimeSpan timeout)
{
ProcessOpen ();
inner_factory.Open (timeout);
}
protected override IAsyncResult OnBeginOpen (TimeSpan timeout, AsyncCallback callback, object state)
{
ProcessOpen ();
return inner_factory.BeginOpen (timeout, callback, state);
}
protected override void OnEndOpen (IAsyncResult result)
{
inner_factory.EndOpen (result);
}
protected override TChannel OnCreateChannel (
EndpointAddress remoteAddress, Uri via)
{
return inner_factory.CreateChannel (remoteAddress, via);
}
protected override void OnClose (TimeSpan timeout)
{
inner_factory.Close (timeout);
txscope.Complete ();
}
}
internal class TransactionChannelListener<TChannel> : ChannelListenerBase<TChannel> where TChannel : class, IChannel
{
IChannelListener<TChannel> inner_listener;
TransactionScope txscope;
TransactionProtocol protocol;
public TransactionChannelListener (IChannelListener<TChannel> innerListener, TransactionProtocol protocol)
{
this.inner_listener = innerListener;
this.protocol = protocol;
}
public override T GetProperty<T> ()
{
return inner_listener.GetProperty<T> () ?? base.GetProperty<T> ();
}
public override Uri Uri {
get { return inner_listener.Uri; }
}
protected override void OnAbort ()
{
inner_listener.Abort ();
}
protected override void OnOpen (TimeSpan timeout)
{
CommittableTransaction tx = new CommittableTransaction ();
txscope = new TransactionScope (tx);
inner_listener.Open (timeout);
}
protected override IAsyncResult OnBeginOpen (TimeSpan timeout, AsyncCallback callback, object state)
{
return inner_listener.BeginOpen (timeout, callback, state);
}
protected override void OnEndOpen (IAsyncResult result)
{
inner_listener.EndOpen (result);
}
protected override void OnClose (TimeSpan timeout)
{
inner_listener.Close (timeout);
txscope.Complete ();
}
protected override IAsyncResult OnBeginClose (TimeSpan timeout, AsyncCallback callback, object state)
{
return inner_listener.BeginClose (timeout, callback, state);
}
protected override void OnEndClose (IAsyncResult result)
{
inner_listener.EndClose (result);
}
protected override bool OnWaitForChannel (TimeSpan timeout)
{
return inner_listener.WaitForChannel (timeout);
}
protected override IAsyncResult OnBeginWaitForChannel (TimeSpan timeout, AsyncCallback callback, object state)
{
return inner_listener.BeginWaitForChannel (timeout, callback, state);
}
protected override bool OnEndWaitForChannel (IAsyncResult result)
{
return inner_listener.EndWaitForChannel (result);
}
protected override TChannel OnAcceptChannel (TimeSpan timeout)
{
return inner_listener.AcceptChannel (timeout);
}
protected override IAsyncResult OnBeginAcceptChannel (TimeSpan timeout,
AsyncCallback callback, object asyncState)
{
return inner_listener.BeginAcceptChannel (timeout, callback, asyncState);
}
protected override TChannel OnEndAcceptChannel (IAsyncResult result)
{
return inner_listener.EndAcceptChannel (result);
}
}
}
|