1 //
2 // ChannelFactoryBase.cs
3 //
4 // Author:
5 //	Atsushi Enomoto  <atsushi@ximian.com>
6 //
7 // Copyright (C) 2005 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 
29 using System;
30 using System.Collections.Generic;
31 using System.Collections.ObjectModel;
32 using System.ServiceModel;
33 using System.ServiceModel.Dispatcher;
34 
35 namespace System.ServiceModel.Channels
36 {
37 	internal interface IHasMessageEncoder
38 	{
39 		MessageEncoder MessageEncoder { get; }
40 	}
41 
42 	internal abstract class TransportChannelFactoryBase<TChannel> : ChannelFactoryBase<TChannel>, IHasMessageEncoder
43 	{
TransportChannelFactoryBase(TransportBindingElement source, BindingContext ctx)44 		protected TransportChannelFactoryBase (TransportBindingElement source, BindingContext ctx)
45 		{
46 			Transport = source;
47 		}
48 
49 		public TransportBindingElement Transport { get; private set; }
50 
51 		public MessageEncoder MessageEncoder { get; internal set; }
52 
53 		Action<TimeSpan> open_delegate;
54 
OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)55 		protected override IAsyncResult OnBeginOpen (TimeSpan timeout,
56 			AsyncCallback callback, object state)
57 		{
58 			if (open_delegate == null)
59 				open_delegate = new Action<TimeSpan> (OnOpen);
60 			return open_delegate.BeginInvoke (timeout, callback, state);
61 		}
62 
OnEndOpen(IAsyncResult result)63 		protected override void OnEndOpen (IAsyncResult result)
64 		{
65 			if (open_delegate == null)
66 				throw new InvalidOperationException ("Async open operation has not started");
67 			open_delegate.EndInvoke (result);
68 		}
69 
OnOpen(TimeSpan timeout)70 		protected override void OnOpen (TimeSpan timeout)
71 		{
72 		}
73 
74 		/* commented out as it is in doubt.
75 		public override T GetProperty<T> ()
76 		{
77 			if (typeof (T) == typeof (MessageVersion))
78 				return (T) (object) MessageEncoder.MessageVersion;
79 			return base.GetProperty<T> ();
80 		}
81 		*/
82 	}
83 
84 	public abstract class ChannelFactoryBase<TChannel>
85 		: ChannelFactoryBase, IChannelFactory<TChannel>
86 	{
87 		List<TChannel> channels = new List<TChannel> ();
88 
ChannelFactoryBase()89 		protected ChannelFactoryBase ()
90 			: this (DefaultCommunicationTimeouts.Instance)
91 		{
92 		}
93 
ChannelFactoryBase( IDefaultCommunicationTimeouts timeouts)94 		protected ChannelFactoryBase (
95 			IDefaultCommunicationTimeouts timeouts)
96 			: base (timeouts)
97 		{
98 		}
99 
CreateChannel( EndpointAddress address)100 		public TChannel CreateChannel (
101 			EndpointAddress address)
102 		{
103 			if (address == null)
104 				throw new ArgumentNullException ("address");
105 			return CreateChannel (address, address.Uri);
106 		}
107 
CreateChannel( EndpointAddress address, Uri via)108 		public TChannel CreateChannel (
109 			EndpointAddress address, Uri via)
110 		{
111 			if (address == null)
112 				throw new ArgumentNullException ("address");
113 			if (via == null)
114 				throw new ArgumentNullException ("via");
115 
116 			ValidateCreateChannel ();
117 			var ch = OnCreateChannel (address, via);
118 			channels.Add (ch);
119 			return ch;
120 		}
121 
OnCreateChannel( EndpointAddress address, Uri via)122 		protected abstract TChannel OnCreateChannel (
123 			EndpointAddress address, Uri via);
124 
OnAbort()125 		protected override void OnAbort ()
126 		{
127 			// this implicitly premises: TChannel is IChannel
128 			foreach (IChannel ch in channels)
129 				ch.Abort ();
130 			base.OnAbort ();
131 		}
132 
OnClose(TimeSpan timeout)133 		protected override void OnClose (TimeSpan timeout)
134 		{
135 			DateTime start = DateTime.UtcNow;
136 			// this implicitly premises: TChannel is IChannel
137 			foreach (IChannel ch in channels)
138 				ch.Close (timeout - (DateTime.UtcNow - start));
139 			base.OnClose (timeout - (DateTime.UtcNow - start));
140 		}
141 
OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)142 		protected override IAsyncResult OnBeginClose (TimeSpan timeout, AsyncCallback callback, object state)
143 		{
144 			// base impl. will call this.OnClose()
145 			// FIXME: use async BeginClose/EndClose on the channels.
146 			return base.OnBeginClose (timeout, callback, state);
147 		}
148 
OnEndClose(IAsyncResult result)149 		protected override void OnEndClose (IAsyncResult result)
150 		{
151 			// base impl. will call this.OnClose()
152 			base.OnEndClose (result);
153 		}
154 
ValidateCreateChannel()155 		protected void ValidateCreateChannel ()
156 		{
157 			ThrowIfDisposedOrNotOpen ();
158 			if (State == CommunicationState.Faulted)
159 				throw new CommunicationObjectFaultedException ();
160 		}
161 	}
162 
163 	public abstract class ChannelFactoryBase
164 		: ChannelManagerBase, IChannelFactory, ICommunicationObject
165 	{
166 		TimeSpan open_timeout, close_timeout, receive_timeout, send_timeout;
167 
ChannelFactoryBase()168 		protected ChannelFactoryBase ()
169 			: this (DefaultCommunicationTimeouts.Instance)
170 		{
171 		}
172 
ChannelFactoryBase( IDefaultCommunicationTimeouts timeouts)173 		protected ChannelFactoryBase (
174 			IDefaultCommunicationTimeouts timeouts)
175 		{
176 			open_timeout = timeouts.OpenTimeout;
177 			close_timeout = timeouts.CloseTimeout;
178 			send_timeout = timeouts.SendTimeout;
179 			receive_timeout = timeouts.ReceiveTimeout;
180 		}
181 
182 		protected internal override TimeSpan DefaultCloseTimeout {
183 			get { return close_timeout; }
184 		}
185 
186 		protected internal override TimeSpan DefaultOpenTimeout {
187 			get { return open_timeout; }
188 		}
189 
190 		protected internal override TimeSpan DefaultReceiveTimeout {
191 			get { return receive_timeout; }
192 		}
193 
194 		protected internal override TimeSpan DefaultSendTimeout {
195 			get { return send_timeout; }
196 		}
197 
198 		public virtual T GetProperty<T> () where T : class
199 		{
200 			return null;
201 		}
202 
OnAbort()203 		protected override void OnAbort ()
204 		{
205 			// what should we do here?
206 		}
207 
208 		Action<TimeSpan> close_delegate;
209 
OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)210 		protected override IAsyncResult OnBeginClose (TimeSpan timeout, AsyncCallback callback, object state)
211 		{
212 			if (close_delegate == null)
213 				close_delegate = new Action<TimeSpan> (OnClose);
214 			return close_delegate.BeginInvoke (timeout, callback, state);
215 		}
216 
OnEndClose(IAsyncResult result)217 		protected override void OnEndClose (IAsyncResult result)
218 		{
219 			if (close_delegate == null)
220 				throw new InvalidOperationException ("Async close operation has not started");
221 			close_delegate.EndInvoke (result);
222 		}
223 
OnClose(TimeSpan timeout)224 		protected override void OnClose (TimeSpan timeout)
225 		{
226 			// what should we do here?
227 		}
228 	}
229 }
230