Merge pull request #5198 from BrzVlad/fix-binprot-stats
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel.Channels / TransactionFlowBindingElement.cs
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]
43                 public TransactionFlowBindingElement ()
44                         : this (TransactionProtocol.Default)
45                 {
46                 }
47
48                 public TransactionFlowBindingElement (TransactionProtocol transactionProtocol)
49                 {
50                         this.protocol = transactionProtocol;
51                 }
52
53                 public TransactionProtocol TransactionProtocol {
54                         get { return protocol; }
55                 }
56
57                 public override BindingElement Clone ()
58                 {
59                         return new TransactionFlowBindingElement (protocol);
60                 }
61
62                 [MonoTODO]
63                 public override T GetProperty<T> (BindingContext context)
64                 {
65                         return context.GetInnerProperty<T> ();
66                 }
67
68                 public override bool CanBuildChannelFactory<TChannel> (BindingContext context)
69                 {
70                         return context.CanBuildInnerChannelFactory<TChannel> ();
71                 }
72
73                 [MonoTODO]
74                 public override bool CanBuildChannelListener<TChannel> (BindingContext context)
75                 {
76                         return context.CanBuildInnerChannelListener<TChannel> ();
77                 }
78
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
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
110                 public TransactionChannelFactory (IChannelFactory<TChannel> innerFactory, TransactionProtocol protocol)
111                 {
112                         this.inner_factory = innerFactory;
113                         this.protocol = protocol;
114                 }
115
116                 void ProcessOpen ()
117                 {
118                         CommittableTransaction tx = new CommittableTransaction ();
119                         txscope = new TransactionScope (tx);
120                 }
121
122                 protected override void OnOpen (TimeSpan timeout)
123                 {
124                         ProcessOpen ();
125                         inner_factory.Open (timeout);
126                 }
127
128                 protected override IAsyncResult OnBeginOpen (TimeSpan timeout, AsyncCallback callback, object state)
129                 {
130                         ProcessOpen ();
131                         return inner_factory.BeginOpen (timeout, callback, state);
132                 }
133
134                 protected override void OnEndOpen (IAsyncResult result)
135                 {
136                         inner_factory.EndOpen (result);
137                 }
138
139                 protected override TChannel OnCreateChannel (
140                         EndpointAddress remoteAddress, Uri via)
141                 {
142                         return inner_factory.CreateChannel (remoteAddress, via);
143                 }
144
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
158                 public TransactionChannelListener (IChannelListener<TChannel> innerListener, TransactionProtocol protocol)
159                 {
160                         this.inner_listener = innerListener;
161                         this.protocol = protocol;
162                 }
163
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
173                 protected override void OnAbort ()
174                 {
175                         inner_listener.Abort ();
176                 }
177
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
185                 protected override IAsyncResult OnBeginOpen (TimeSpan timeout, AsyncCallback callback, object state)
186                 {
187                         return inner_listener.BeginOpen (timeout, callback, state);
188                 }
189
190                 protected override void OnEndOpen (IAsyncResult result)
191                 {
192                         inner_listener.EndOpen (result);
193                 }
194
195                 protected override void OnClose (TimeSpan timeout)
196                 {
197                         inner_listener.Close (timeout);
198                         txscope.Complete ();
199                 }
200
201                 protected override IAsyncResult OnBeginClose (TimeSpan timeout, AsyncCallback callback, object state)
202                 {
203                         return inner_listener.BeginClose (timeout, callback, state);
204                 }
205
206                 protected override void OnEndClose (IAsyncResult result)
207                 {
208                         inner_listener.EndClose (result);
209                 }
210
211                 protected override bool OnWaitForChannel (TimeSpan timeout)
212                 {
213                         return inner_listener.WaitForChannel (timeout);
214                 }
215
216                 protected override IAsyncResult OnBeginWaitForChannel (TimeSpan timeout, AsyncCallback callback, object state)
217                 {
218                         return inner_listener.BeginWaitForChannel (timeout, callback, state);
219                 }
220
221                 protected override bool OnEndWaitForChannel (IAsyncResult result)
222                 {
223                         return inner_listener.EndWaitForChannel (result);
224                 }
225
226                 protected override TChannel OnAcceptChannel (TimeSpan timeout)
227                 {
228                         return inner_listener.AcceptChannel (timeout);
229                 }
230
231                 protected override IAsyncResult OnBeginAcceptChannel (TimeSpan timeout,
232                         AsyncCallback callback, object asyncState)
233                 {
234                         return inner_listener.BeginAcceptChannel (timeout, callback, asyncState);
235                 }
236
237                 protected override TChannel OnEndAcceptChannel (IAsyncResult result)
238                 {
239                         return inner_listener.EndAcceptChannel (result);
240                 }
241         }
242 }