1 //
2 // TransactionFlowBindingElement.cs
3 //
4 // Author:
5 //	Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2006 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.Collections.Generic;
30 using System.ServiceModel.Description;
31 using System.ServiceModel.Security;
32 using System.ServiceModel.Channels;
33 using System.Transactions;
34 
35 namespace System.ServiceModel.Channels
36 {
37 	public class TransactionFlowBindingElement : BindingElement
38 	{
39 		TransactionProtocol protocol;
40 
41 		// Funny, but since it uses OLE TX, Mono will never support this constructor.
42 		[MonoTODO]
TransactionFlowBindingElement()43 		public TransactionFlowBindingElement ()
44 			: this (TransactionProtocol.Default)
45 		{
46 		}
47 
TransactionFlowBindingElement(TransactionProtocol transactionProtocol)48 		public TransactionFlowBindingElement (TransactionProtocol transactionProtocol)
49 		{
50 			this.protocol = transactionProtocol;
51 		}
52 
53 		public TransactionProtocol TransactionProtocol {
54 			get { return protocol; }
55 		}
56 
Clone()57 		public override BindingElement Clone ()
58 		{
59 			return new TransactionFlowBindingElement (protocol);
60 		}
61 
62 		[MonoTODO]
GetProperty(BindingContext context)63 		public override T GetProperty<T> (BindingContext context)
64 		{
65 			return context.GetInnerProperty<T> ();
66 		}
67 
CanBuildChannelFactory(BindingContext context)68 		public override bool CanBuildChannelFactory<TChannel> (BindingContext context)
69 		{
70 			return context.CanBuildInnerChannelFactory<TChannel> ();
71 		}
72 
73 		[MonoTODO]
CanBuildChannelListener(BindingContext context)74 		public override bool CanBuildChannelListener<TChannel> (BindingContext context)
75 		{
76 			return context.CanBuildInnerChannelListener<TChannel> ();
77 		}
78 
BuildChannelFactory(BindingContext context)79 		public override IChannelFactory<TChannel> BuildChannelFactory<TChannel> (BindingContext context)
80 		{
81 			if (protocol == null)
82 				throw new InvalidOperationException ("Set transaction protocol in prior to build a channel factory.");
83 			if (protocol == TransactionProtocol.Default)
84 				throw new NotSupportedException ("Mono does not support DTC.");
85 			if (!CanBuildChannelFactory<TChannel> (context.Clone ()))
86 				throw new ArgumentException (String.Format ("The channel type '{0}' is not supported", typeof (TChannel)));
87 			return new TransactionChannelFactory<TChannel> (context.BuildInnerChannelFactory<TChannel> (), protocol);
88 		}
89 
BuildChannelListener(BindingContext context)90 		public override IChannelListener<TChannel> BuildChannelListener<TChannel> (BindingContext context)
91 		{
92 			if (protocol == null)
93 				throw new InvalidOperationException ("Set transaction protocol in prior to build a channel listener.");
94 			if (protocol == TransactionProtocol.Default)
95 				throw new NotSupportedException ("Mono does not support DTC.");
96 			if (!CanBuildChannelListener<TChannel> (context.Clone ()))
97 				throw new ArgumentException (String.Format ("The channel type '{0}' is not supported", typeof (TChannel)));
98 			return new TransactionChannelListener<TChannel> (
99 				context.BuildInnerChannelListener<TChannel> (),
100 				protocol);
101 		}
102 	}
103 
104 	internal class TransactionChannelFactory<TChannel> : ChannelFactoryBase<TChannel>
105 	{
106 		IChannelFactory<TChannel> inner_factory;
107 		TransactionScope txscope;
108 		TransactionProtocol protocol;
109 
TransactionChannelFactory(IChannelFactory<TChannel> innerFactory, TransactionProtocol protocol)110 		public TransactionChannelFactory (IChannelFactory<TChannel> innerFactory, TransactionProtocol protocol)
111 		{
112 			this.inner_factory = innerFactory;
113 			this.protocol = protocol;
114 		}
115 
ProcessOpen()116 		void ProcessOpen ()
117 		{
118 			CommittableTransaction tx = new CommittableTransaction ();
119 			txscope = new TransactionScope (tx);
120 		}
121 
OnOpen(TimeSpan timeout)122 		protected override void OnOpen (TimeSpan timeout)
123 		{
124 			ProcessOpen ();
125 			inner_factory.Open (timeout);
126 		}
127 
OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)128 		protected override IAsyncResult OnBeginOpen (TimeSpan timeout, AsyncCallback callback, object state)
129 		{
130 			ProcessOpen ();
131 			return inner_factory.BeginOpen (timeout, callback, state);
132 		}
133 
OnEndOpen(IAsyncResult result)134 		protected override void OnEndOpen (IAsyncResult result)
135 		{
136 			inner_factory.EndOpen (result);
137 		}
138 
OnCreateChannel( EndpointAddress remoteAddress, Uri via)139 		protected override TChannel OnCreateChannel (
140 			EndpointAddress remoteAddress, Uri via)
141 		{
142 			return inner_factory.CreateChannel (remoteAddress, via);
143 		}
144 
OnClose(TimeSpan timeout)145 		protected override void OnClose (TimeSpan timeout)
146 		{
147 			inner_factory.Close (timeout);
148 			txscope.Complete ();
149 		}
150 	}
151 
152 	internal class TransactionChannelListener<TChannel> : ChannelListenerBase<TChannel> where TChannel : class, IChannel
153 	{
154 		IChannelListener<TChannel> inner_listener;
155 		TransactionScope txscope;
156 		TransactionProtocol protocol;
157 
TransactionChannelListener(IChannelListener<TChannel> innerListener, TransactionProtocol protocol)158 		public TransactionChannelListener (IChannelListener<TChannel> innerListener, TransactionProtocol protocol)
159 		{
160 			this.inner_listener = innerListener;
161 			this.protocol = protocol;
162 		}
163 
GetProperty()164 		public override T GetProperty<T> ()
165 		{
166 			return inner_listener.GetProperty<T> () ?? base.GetProperty<T> ();
167 		}
168 
169 		public override Uri Uri {
170 			get { return inner_listener.Uri; }
171 		}
172 
OnAbort()173 		protected override void OnAbort ()
174 		{
175 			inner_listener.Abort ();
176 		}
177 
OnOpen(TimeSpan timeout)178 		protected override void OnOpen (TimeSpan timeout)
179 		{
180 			CommittableTransaction tx = new CommittableTransaction ();
181 			txscope = new TransactionScope (tx);
182 			inner_listener.Open (timeout);
183 		}
184 
OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)185 		protected override IAsyncResult OnBeginOpen (TimeSpan timeout, AsyncCallback callback, object state)
186 		{
187 			return inner_listener.BeginOpen (timeout, callback, state);
188 		}
189 
OnEndOpen(IAsyncResult result)190 		protected override void OnEndOpen (IAsyncResult result)
191 		{
192 			inner_listener.EndOpen (result);
193 		}
194 
OnClose(TimeSpan timeout)195 		protected override void OnClose (TimeSpan timeout)
196 		{
197 			inner_listener.Close (timeout);
198 			txscope.Complete ();
199 		}
200 
OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)201 		protected override IAsyncResult OnBeginClose (TimeSpan timeout, AsyncCallback callback, object state)
202 		{
203 			return inner_listener.BeginClose (timeout, callback, state);
204 		}
205 
OnEndClose(IAsyncResult result)206 		protected override void OnEndClose (IAsyncResult result)
207 		{
208 			inner_listener.EndClose (result);
209 		}
210 
OnWaitForChannel(TimeSpan timeout)211 		protected override bool OnWaitForChannel (TimeSpan timeout)
212 		{
213 			return inner_listener.WaitForChannel (timeout);
214 		}
215 
OnBeginWaitForChannel(TimeSpan timeout, AsyncCallback callback, object state)216 		protected override IAsyncResult OnBeginWaitForChannel (TimeSpan timeout, AsyncCallback callback, object state)
217 		{
218 			return inner_listener.BeginWaitForChannel (timeout, callback, state);
219 		}
220 
OnEndWaitForChannel(IAsyncResult result)221 		protected override bool OnEndWaitForChannel (IAsyncResult result)
222 		{
223 			return inner_listener.EndWaitForChannel (result);
224 		}
225 
OnAcceptChannel(TimeSpan timeout)226 		protected override TChannel OnAcceptChannel (TimeSpan timeout)
227 		{
228 			return inner_listener.AcceptChannel (timeout);
229 		}
230 
OnBeginAcceptChannel(TimeSpan timeout, AsyncCallback callback, object asyncState)231 		protected override IAsyncResult OnBeginAcceptChannel (TimeSpan timeout,
232 			AsyncCallback callback, object asyncState)
233 		{
234 			return inner_listener.BeginAcceptChannel (timeout, callback, asyncState);
235 		}
236 
OnEndAcceptChannel(IAsyncResult result)237 		protected override TChannel OnEndAcceptChannel (IAsyncResult result)
238 		{
239 			return inner_listener.EndAcceptChannel (result);
240 		}
241 	}
242 }
243