| | 1 | | /* |
| | 2 | | * Copyright 2017 Stanislav Muhametsin. All rights Reserved. |
| | 3 | | * |
| | 4 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | 5 | | * you may not use this file except in compliance with the License. |
| | 6 | | * You may obtain a copy of the License at |
| | 7 | | * |
| | 8 | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | 9 | | * |
| | 10 | | * Unless required by applicable law or agreed to in writing, software |
| | 11 | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | 12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| | 13 | | * implied. |
| | 14 | | * |
| | 15 | | * See the License for the specific language governing permissions and |
| | 16 | | * limitations under the License. |
| | 17 | | */ |
| | 18 | | using CBAM.Abstractions; |
| | 19 | | using CBAM.Abstractions.Implementation; |
| | 20 | | using ResourcePooling.Async.Abstractions; |
| | 21 | | using System; |
| | 22 | | using System.Collections.Generic; |
| | 23 | | using System.Text; |
| | 24 | | using System.Threading; |
| | 25 | | using System.Threading.Tasks; |
| | 26 | | using UtilPack; |
| | 27 | |
|
| | 28 | | namespace CBAM.Abstractions.Implementation |
| | 29 | | { |
| | 30 | | /// <summary> |
| | 31 | | /// This class implements <see cref="AsyncResourceFactory{TResource, TParams}"/> in order to create instances of <see |
| | 32 | | /// </summary> |
| | 33 | | /// <typeparam name="TConnection">The public type of <see cref="Connection{TStatement, TStatementInformation, TStatem |
| | 34 | | /// <typeparam name="TPrivateConnection">The actual type of <see cref="Connection{TStatement, TStatementInformation, |
| | 35 | | /// <typeparam name="TConnectionFunctionality">The actual type of <see cref="PooledConnectionFunctionality"/>.</typep |
| | 36 | | /// <typeparam name="TConnectionCreationParameters">The type of parameter containing enough information to create an |
| | 37 | | public abstract class DefaultConnectionFactory<TConnection, TPrivateConnection, TConnectionFunctionality, TConnection |
| | 38 | | where TConnection : class |
| | 39 | | where TPrivateConnection : class, TConnection |
| | 40 | | where TConnectionFunctionality : class, PooledConnectionFunctionality |
| | 41 | | { |
| | 42 | | /// <summary> |
| | 43 | | /// Initializes a new instance of <see cref="PooledConnectionFunctionality"/> with given connection creation param |
| | 44 | | /// </summary> |
| | 45 | | /// <param name="creationParameters">The connection creation parameters.</param> |
| | 46 | | public DefaultConnectionFactory( |
| | 47 | | TConnectionCreationParameters creationParameters |
| 27 | 48 | | ) : base( creationParameters ) |
| | 49 | | { |
| | 50 | |
|
| 27 | 51 | | } |
| | 52 | |
|
| | 53 | |
|
| | 54 | | /// <summary> |
| | 55 | | /// This method implements <see cref="DefaultBoundAsyncResourceFactory{TConnection, TConnectionCreationParameters} |
| | 56 | | /// </summary> |
| | 57 | | /// <param name="token">The <see cref="CancellationToken"/> to use.</param> |
| | 58 | | /// <returns>Potentially asynchronously returns <see cref="AsyncResourceAcquireInfo{TResource}"/> for given resour |
| | 59 | | /// <remarks> |
| | 60 | | /// The methods called are, in this order: |
| | 61 | | /// <list type="number"> |
| | 62 | | /// <item><description>the <see cref="CreateConnectionFunctionality(CancellationToken)"/>,</description></item> |
| | 63 | | /// <item><description>the <see cref="CreateConnection(TConnectionFunctionality)"/>, and</description></item> |
| | 64 | | /// <item><description>the <see cref="CreateConnectionAcquireInfo(TConnectionFunctionality, TPrivateConnection)"/> |
| | 65 | | /// </list> |
| | 66 | | /// |
| | 67 | | /// In case of an error, the <see cref="OnConnectionAcquirementError(TConnectionFunctionality, TPrivateConnection, |
| | 68 | | /// </remarks> |
| | 69 | | protected override async ValueTask<AsyncResourceAcquireInfo<TConnection>> AcquireResourceAsync( CancellationToken |
| | 70 | | { |
| 30 | 71 | | TConnectionFunctionality functionality = null; |
| 30 | 72 | | TPrivateConnection connection = null; |
| | 73 | | try |
| | 74 | | { |
| 30 | 75 | | functionality = await this.CreateConnectionFunctionality( token ); |
| 30 | 76 | | functionality.CurrentCancellationToken = token; |
| 30 | 77 | | connection = await this.CreateConnection( functionality ); |
| 30 | 78 | | return this.CreateConnectionAcquireInfo( functionality, connection ); |
| | 79 | | } |
| 0 | 80 | | catch ( Exception exc ) |
| | 81 | | { |
| | 82 | | try |
| | 83 | | { |
| 0 | 84 | | await this.OnConnectionAcquirementError( functionality, connection, token, exc ); |
| 0 | 85 | | } |
| 0 | 86 | | catch |
| | 87 | | { |
| | 88 | | // Ignore this one |
| 0 | 89 | | } |
| 0 | 90 | | throw; |
| | 91 | | } |
| | 92 | | finally |
| | 93 | | { |
| 30 | 94 | | functionality?.ResetCancellationToken(); |
| | 95 | | } |
| 30 | 96 | | } |
| | 97 | |
|
| | 98 | |
|
| | 99 | | /// <summary> |
| | 100 | | /// This method is called by <see cref="AcquireResourceAsync(CancellationToken)"/> initially, to create <see cref= |
| | 101 | | /// </summary> |
| | 102 | | /// <param name="token">The <see cref="CancellationToken"/> to use.</param> |
| | 103 | | /// <returns>A task which will result in <see cref="PooledConnectionFunctionality"/> when completed.</returns> |
| | 104 | | protected abstract ValueTask<TConnectionFunctionality> CreateConnectionFunctionality( CancellationToken token ); |
| | 105 | |
|
| | 106 | | /// <summary> |
| | 107 | | /// This method is called after <see cref="CreateConnectionFunctionality(CancellationToken)"/>, in order to create |
| | 108 | | /// </summary> |
| | 109 | | /// <param name="functionality">The <see cref="PooledConnectionFunctionality"/> created by <see cref="CreateConnec |
| | 110 | | /// <returns>A task which will result in <see cref="ConnectionImpl{TStatement, TStatementInformation, TStatementCr |
| | 111 | | protected abstract ValueTask<TPrivateConnection> CreateConnection( TConnectionFunctionality functionality ); |
| | 112 | |
|
| | 113 | | /// <summary> |
| | 114 | | /// This method is called after <see cref="CreateConnection(TConnectionFunctionality)"/> in order to create instan |
| | 115 | | /// </summary> |
| | 116 | | /// <param name="functionality">The <see cref="PooledConnectionFunctionality"/> created by <see cref="CreateConnec |
| | 117 | | /// <param name="connection">The <see cref="ConnectionImpl{TStatement, TStatementInformation, TStatementCreationAr |
| | 118 | | /// <returns>A new instance of <see cref="AsyncResourceAcquireInfo{TResource}"/>.</returns> |
| | 119 | | protected abstract AsyncResourceAcquireInfo<TPrivateConnection> CreateConnectionAcquireInfo( TConnectionFunctional |
| | 120 | |
|
| | 121 | | /// <summary> |
| | 122 | | /// This method is called whenever an error occurs within <see cref="AcquireResourceAsync(CancellationToken)"/> me |
| | 123 | | /// </summary> |
| | 124 | | /// <param name="functionality">The <see cref="PooledConnectionFunctionality"/> or <c>null</c> if error occurred d |
| | 125 | | /// <param name="connection">The <see cref="ConnectionImpl{TStatement, TStatementInformation, TStatementCreationAr |
| | 126 | | /// <param name="token">The <see cref="CancellationToken"/> passed to <see cref="AcquireResourceAsync(Cancellation |
| | 127 | | /// <param name="error">The error which occurred.</param> |
| | 128 | | /// <returns>A task which completes after error handling is done.</returns> |
| | 129 | | protected abstract Task OnConnectionAcquirementError( TConnectionFunctionality functionality, TPrivateConnection c |
| | 130 | | } |
| | 131 | |
|
| | 132 | | /// <summary> |
| | 133 | | /// This class provides CBAM-related implementation for <see cref="AsyncResourceAcquireInfoImpl{TConnection, TChannel |
| | 134 | | /// </summary> |
| | 135 | | /// <typeparam name="TConnection">The actual type of <see cref="ConnectionImpl{TConnectionFunctionality}"/>.</typepar |
| | 136 | | /// <typeparam name="TConnectionFunctionality">The actual type of <see cref="PooledConnectionFunctionality"/>.</typep |
| | 137 | | /// <typeparam name="TStream">The actual type of underlying stream or other disposable resource.</typeparam> |
| | 138 | | public abstract class ConnectionAcquireInfoImpl<TConnection, TConnectionFunctionality, TStream> : AsyncResourceAcquir |
| | 139 | | where TConnection : class |
| | 140 | | where TConnectionFunctionality : class, PooledConnectionFunctionality |
| | 141 | | where TStream : IDisposable |
| | 142 | | { |
| | 143 | | /// <summary> |
| | 144 | | /// Creates a new instance of <see cref="ConnectionAcquireInfoImpl{TConnection, TConnectionFunctionality, TStream} |
| | 145 | | /// </summary> |
| | 146 | | /// <param name="connection">The <typeparamref name="TConnection"/>.</param> |
| | 147 | | /// <param name="functionality">The <typeparamref name="TConnectionFunctionality"/>.</param> |
| | 148 | | /// <param name="associatedStream">The underlying stream or other disposable resource.</param> |
| | 149 | | /// <exception cref="ArgumentNullException">If <paramref name="connection"/> is <c>null</c>.</exception> |
| | 150 | | public ConnectionAcquireInfoImpl( |
| | 151 | | TConnection connection, |
| | 152 | | TConnectionFunctionality functionality, |
| | 153 | | TStream associatedStream |
| | 154 | | ) : base( ArgumentValidator.ValidateNotNull( nameof( connection ), connection ), associatedStream, ( c, t ) => |
| | 155 | | { |
| | 156 | | this.Functionality = ArgumentValidator.ValidateNotNull( nameof( functionality ), functionality ); |
| | 157 | | } |
| | 158 | |
|
| | 159 | | /// <summary> |
| | 160 | | /// Gets the <typeparamref name="TConnectionFunctionality"/> of this <see cref="ConnectionAcquireInfoImpl{TConnect |
| | 161 | | /// </summary> |
| | 162 | | /// <value>The <typeparamref name="TConnectionFunctionality"/> of this <see cref="ConnectionAcquireInfoImpl{TConne |
| | 163 | | protected TConnectionFunctionality Functionality { get; } |
| | 164 | |
|
| | 165 | | /// <summary> |
| | 166 | | /// This method overrides <see cref="AbstractDisposable.Dispose(Boolean)"/> and will dispose this <see cref="Async |
| | 167 | | /// </summary> |
| | 168 | | /// <param name="disposing">Whether this method is callsed from <see cref="IDisposable.Dispose"/> method.</param> |
| | 169 | | protected override void Dispose( Boolean disposing ) |
| | 170 | | { |
| | 171 | | if ( disposing ) |
| | 172 | | { |
| | 173 | | this.Channel?.DisposeSafely(); |
| | 174 | | } |
| | 175 | | } |
| | 176 | |
|
| | 177 | | /// <summary> |
| | 178 | | /// Overrides the abstract <see cref="AsyncResourceAcquireInfoImpl{TConnection, TStream}.PublicResourceCanBeReturn |
| | 179 | | /// </summary> |
| | 180 | | /// <returns>The value indicating whether this <see cref="ConnectionAcquireInfoImpl{TConnection, TConnectionFuncti |
| | 181 | | protected override Boolean PublicResourceCanBeReturnedToPool() |
| | 182 | | { |
| | 183 | | return this.Functionality.CanBeReturnedToPool; |
| | 184 | | } |
| | 185 | |
|
| | 186 | | } |
| | 187 | |
|
| | 188 | | /// <summary> |
| | 189 | | /// This class extends <see cref="ConnectionAcquireInfoImpl{TConnection, TConnectionFunctionality, TStream}"/> for si |
| | 190 | | /// </summary> |
| | 191 | | /// <typeparam name="TConnection">The actual type of <see cref="ConnectionImpl{TConnectionFunctionality}"/>.</typepar |
| | 192 | | /// <typeparam name="TConnectionFunctionality">The actual type of <see cref="PooledConnectionFunctionality"/>.</typep |
| | 193 | | /// <typeparam name="TStream">The actual type of underlying stream or other disposable resource.</typeparam> |
| | 194 | | public sealed class StatelessConnectionAcquireInfo<TConnection, TConnectionFunctionality, TStream> : ConnectionAcquir |
| | 195 | | where TConnection : class |
| | 196 | | where TConnectionFunctionality : class, PooledConnectionFunctionality |
| | 197 | | where TStream : IDisposable |
| | 198 | | { |
| | 199 | | /// <summary> |
| | 200 | | /// Creates a new instance of <see cref="StatelessConnectionAcquireInfo{TConnection, TConnectionFunctionality, TSt |
| | 201 | | /// </summary> |
| | 202 | | /// <param name="connection">The <typeparamref name="TConnection"/>.</param> |
| | 203 | | /// <param name="functionality">The <typeparamref name="TConnectionFunctionality"/>.</param> |
| | 204 | | /// <param name="associatedStream">The underlying stream or other disposable resource.</param> |
| | 205 | | /// <exception cref="ArgumentNullException">If <paramref name="connection"/> is <c>null</c>.</exception> |
| | 206 | | public StatelessConnectionAcquireInfo( |
| | 207 | | TConnection connection, |
| | 208 | | TConnectionFunctionality functionality, |
| | 209 | | TStream associatedStream |
| | 210 | | ) : base( connection, functionality, associatedStream ) |
| | 211 | | { |
| | 212 | | } |
| | 213 | |
|
| | 214 | | /// <summary> |
| | 215 | | /// This method does nothing and returns completed task, since there should be nothing to do. |
| | 216 | | /// </summary> |
| | 217 | | /// <param name="token">The <see cref="CancellationToken"/> to use.</param> |
| | 218 | | /// <returns>Always returns completed task.</returns> |
| | 219 | | protected override Task DisposeBeforeClosingChannel( CancellationToken token ) |
| | 220 | | { |
| | 221 | | return TaskUtils.CompletedTask; |
| | 222 | | } |
| | 223 | | } |
| | 224 | |
|
| | 225 | |
|
| | 226 | | /// <summary> |
| | 227 | | /// This class extends <see cref="DefaultConnectionFactory{TConnection, TPrivateConnection, TConnectionCreationParame |
| | 228 | | /// </summary> |
| | 229 | | /// <typeparam name="TConnection">The public type of <see cref="Connection{TStatement, TStatementInformation, TStatem |
| | 230 | | /// <typeparam name="TPrivateConnection">The actual type of <see cref="Connection{TStatement, TStatementInformation, |
| | 231 | | /// <typeparam name="TConnectionFunctionality">The actual type of <see cref="PooledConnectionFunctionality{TStatement |
| | 232 | | /// <typeparam name="TConnectionCreationParameters">The type of parameter containing enough information to create an |
| | 233 | | public abstract class ConnectionFactoryStream<TConnection, TPrivateConnection, TConnectionFunctionality, TConnectionC |
| | 234 | | where TConnection : class |
| | 235 | | where TPrivateConnection : class, TConnection |
| | 236 | | where TConnectionFunctionality : class, PooledConnectionFunctionality |
| | 237 | | { |
| | 238 | | /// <summary> |
| | 239 | | /// Initializes a new instance of <see cref="ConnectionFactoryStream{TConnection, TPrivateConnection, TConnectionC |
| | 240 | | /// </summary> |
| | 241 | | /// <param name="creationParameters">The connection creation parameters.</param> |
| | 242 | | public ConnectionFactoryStream( |
| | 243 | | TConnectionCreationParameters creationParameters |
| | 244 | | ) : base( creationParameters ) |
| | 245 | | { |
| | 246 | | } |
| | 247 | |
|
| | 248 | | /// <summary> |
| | 249 | | /// This task overrides <see cref="DefaultConnectionFactory{TConnection, TPrivateConnection, TConnectionCreationPa |
| | 250 | | /// </summary> |
| | 251 | | /// <param name="functionality">The <see cref="PooledConnectionFunctionality{TStatement, TStatementInformation, TS |
| | 252 | | /// <param name="connection">The <see cref="ConnectionImpl{TStatement, TStatementInformation, TStatementCreationAr |
| | 253 | | /// <param name="token">The <see cref="CancellationToken"/> passed to <see cref="DefaultConnectionFactory{TConnect |
| | 254 | | /// <param name="error">The error which occurred.</param> |
| | 255 | | /// <returns>A completed task.</returns> |
| | 256 | | protected override Task OnConnectionAcquirementError( TConnectionFunctionality functionality, TPrivateConnection c |
| | 257 | | { |
| | 258 | | this.ExtractStreamOnConnectionAcquirementError( functionality, connection, token, error ).DisposeSafely(); |
| | 259 | | return TaskUtils.CompletedTask; |
| | 260 | | } |
| | 261 | |
|
| | 262 | | /// <summary> |
| | 263 | | /// This method should be implemented by derived class in order to extract underlying stream or other <see cref="I |
| | 264 | | /// </summary> |
| | 265 | | /// <param name="functionality">The <see cref="PooledConnectionFunctionality{TStatement, TStatementInformation, TS |
| | 266 | | /// <param name="connection">The <see cref="ConnectionImpl{TStatement, TStatementInformation, TStatementCreationAr |
| | 267 | | /// <param name="token">The <see cref="CancellationToken"/> passed to <see cref="DefaultConnectionFactory{TConnect |
| | 268 | | /// <param name="error">The error which occurred.</param> |
| | 269 | | /// <returns>The underlying stream or other <see cref="IDisposable"/> object.</returns> |
| | 270 | | protected abstract IDisposable ExtractStreamOnConnectionAcquirementError( TConnectionFunctionality functionality, |
| | 271 | | } |
| | 272 | |
|
| | 273 | | } |