SPRNET-1240 - Add TransientDataAccessException to DAO exception hierarchy

This commit is contained in:
markpollack
2009-07-28 20:56:50 +00:00
parent 7b8ea2a7ea
commit aa30032e3d
7 changed files with 699 additions and 474 deletions

View File

@@ -26,22 +26,22 @@ using System.Runtime.Serialization;
#endregion
namespace Spring.Dao
{
/// <summary>
/// Exception thrown on concurrency failure. This exception should be
/// sublassed to indicate the type of failure - optimistic locking,
/// failure to acquire lock, etc.
/// </summary>
/// <remarks>
/// <p>
/// This exception will be thrown either by O/R mapping tools or by custom DAO
/// implementations.
/// </p>
/// </remarks>
/// <author>Thomas Risberg</author>
/// <author>Griffin Caprio (.NET)</author>
{
/// <summary>
/// Exception thrown on concurrency failure. This exception should be
/// sublassed to indicate the type of failure - optimistic locking,
/// failure to acquire lock, etc.
/// </summary>
/// <remarks>
/// <p>
/// This exception will be thrown either by O/R mapping tools or by custom DAO
/// implementations.
/// </p>
/// </remarks>
/// <author>Thomas Risberg</author>
/// <author>Griffin Caprio (.NET)</author>
[Serializable]
public class ConcurrencyFailureException : DataAccessException
public class ConcurrencyFailureException : TransientDataAccessException
{
/// <summary>
/// Creates a new instance of the
@@ -82,8 +82,8 @@ namespace Spring.Dao
/// <param name="context">
/// The <see cref="System.Runtime.Serialization.StreamingContext"/>
/// that contains contextual information about the source or destination.
/// </param>
protected ConcurrencyFailureException(
/// </param>
protected ConcurrencyFailureException(
SerializationInfo info, StreamingContext context ) : base( info, context ) {}
}
}

View File

@@ -0,0 +1,83 @@
#region License
/*
* Copyright 2002-2004 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
#region Imports
using System;
using System.Runtime.Serialization;
#endregion
namespace Spring.Dao
{
/// <summary>
/// Root of the hierarchy of data access exception that are considered transient -
/// where a previously failed operation might be able to succeed when the operation
/// is retried without any intervention by application-level functionality.
/// </summary>
/// <author>Thomas Risberg</author>
/// <author>Mark Pollack (.NET)</author>
[Serializable]
public abstract class TransientDataAccessException : DataAccessException
{
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Dao.TransientDataAccessException"/> class.
/// </summary>
public TransientDataAccessException() : base("No Exception Message") {}
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Dao.TransientDataAccessException"/> class.
/// </summary>
/// <param name="message">
/// A message about the exception.
/// </param>
public TransientDataAccessException( string message ) : base( message ) {}
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Dao.TransientDataAccessException"/> class.
/// </summary>
/// <param name="message">
/// A message about the exception.
/// </param>
/// <param name="rootCause">
/// The root exception (from the underlying data access API, such as ADO.NET).
/// </param>
public TransientDataAccessException( string message, Exception rootCause)
: base( message , rootCause ) {}
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Dao.TransientDataAccessException"/> class.
/// </summary>
/// <param name="info">
/// The <see cref="System.Runtime.Serialization.SerializationInfo"/>
/// that holds the serialized object data about the exception being thrown.
/// </param>
/// <param name="context">
/// The <see cref="System.Runtime.Serialization.StreamingContext"/>
/// that contains contextual information about the source or destination.
/// </param>
protected TransientDataAccessException(
SerializationInfo info, StreamingContext context ) : base( info, context ) {}
}
}

View File

@@ -0,0 +1,82 @@
#region License
/*
* Copyright 2002-2004 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
#region Imports
using System;
using System.Runtime.Serialization;
#endregion
namespace Spring.Dao
{
/// <summary>
/// RDta access exception thrown when a resource fails temporarily and the operation can be
/// retried.
/// </summary>
/// <author>Thomas Risberg</author>
/// <author>Mark Pollack (.NET)</author>
[Serializable]
public class TransientDataAccessResourceException : TransientDataAccessException
{
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Dao.TransientDataAccessResourceException"/> class.
/// </summary>
public TransientDataAccessResourceException() : base("No Exception Message") {}
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Dao.TransientDataAccessResourceException"/> class.
/// </summary>
/// <param name="message">
/// A message about the exception.
/// </param>
public TransientDataAccessResourceException( string message ) : base( message ) {}
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Dao.TransientDataAccessResourceException"/> class.
/// </summary>
/// <param name="message">
/// A message about the exception.
/// </param>
/// <param name="rootCause">
/// The root exception (from the underlying data access API, such as ADO.NET).
/// </param>
public TransientDataAccessResourceException( string message, Exception rootCause)
: base( message , rootCause ) {}
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Dao.TransientDataAccessResourceException"/> class.
/// </summary>
/// <param name="info">
/// The <see cref="System.Runtime.Serialization.SerializationInfo"/>
/// that holds the serialized object data about the exception being thrown.
/// </param>
/// <param name="context">
/// The <see cref="System.Runtime.Serialization.StreamingContext"/>
/// that contains contextual information about the source or destination.
/// </param>
protected TransientDataAccessResourceException(
SerializationInfo info, StreamingContext context ) : base( info, context ) {}
}
}

View File

@@ -1,159 +1,167 @@
#region Licence
/*
* Copyright <20> 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
#region Imports
using System;
using Common.Logging;
#endregion
namespace Spring.Data.Common
{
/// <summary>
/// Holds ADO.NET error codes for a particular provider.
/// </summary>
/// <remarks>
/// Used by ErrorCodeExceptionTranslator. The embedded resource
/// "dbProviders.xml" in Spring.Data.Common contains default
/// ErrorCodes instances for various providers.
/// </remarks>
/// <author>Mark Pollack (.NET)</author>
public class ErrorCodes
{
#region Fields
private string[] databaseProductNames;
private string[] badSqlGrammarCodes = new String[0];
private string[] invalidResultSetAccessCodes = new String[0];
private string[] dataAccessResourceFailureCodes = new String[0];
private string[] permissionDeniedCodes = new String[0];
private string[] dataIntegrityViolationCodes = new String[0];
private string[] cannotAcquireLockCodes = new String[0];
private string[] deadlockLoserCodes = new String[0];
private string[] cannotSerializeTransactionCodes = new String[0];
private string[] duplicateKeyCodes = new string[0];
// CustomErrorCodesTranslation[] customTranslations;
#endregion
#region Constants
/// <summary>
/// The shared log instance for this class (and derived classes).
/// </summary>
protected static readonly ILog log =
LogManager.GetLogger(typeof (ErrorCodes));
#endregion
#region Constructor (s)
/// <summary>
/// Initializes a new instance of the <see cref="ErrorCodes"/> class.
/// </summary>
public ErrorCodes()
{
}
#endregion
#region Properties
public string DatabaseProductName
{
get
{
return (databaseProductNames != null && databaseProductNames.Length > 0 ?
databaseProductNames[0] : null);
}
}
public string[] DatabaseProductNames
{
get { return databaseProductNames; }
set { databaseProductNames = value; }
}
public string[] BadSqlGrammarCodes
{
get { return badSqlGrammarCodes; }
set { badSqlGrammarCodes = value; }
}
public string[] InvalidResultSetAccessCodes
{
get { return invalidResultSetAccessCodes; }
set { invalidResultSetAccessCodes = value; }
}
public string[] DataAccessResourceFailureCodes
{
get { return dataAccessResourceFailureCodes; }
set { dataAccessResourceFailureCodes = value; }
}
public string[] PermissionDeniedCodes
{
get { return permissionDeniedCodes; }
set { permissionDeniedCodes = value; }
}
public string[] DataIntegrityViolationCodes
{
get { return dataIntegrityViolationCodes; }
set { dataIntegrityViolationCodes = value; }
}
public string[] CannotAcquireLockCodes
{
get { return cannotAcquireLockCodes; }
set { cannotAcquireLockCodes = value; }
}
public string[] DeadlockLoserCodes
{
get { return deadlockLoserCodes; }
set { deadlockLoserCodes = value; }
}
public string[] CannotSerializeTransactionCodes
{
get { return cannotSerializeTransactionCodes; }
set { cannotSerializeTransactionCodes = value; }
}
#region Licence
/*
* Copyright <20> 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
#region Imports
using System;
using Common.Logging;
#endregion
namespace Spring.Data.Common
{
/// <summary>
/// Holds ADO.NET error codes for a particular provider.
/// </summary>
/// <remarks>
/// Used by ErrorCodeExceptionTranslator. The embedded resource
/// "dbProviders.xml" in Spring.Data.Common contains default
/// ErrorCodes instances for various providers.
/// </remarks>
/// <author>Mark Pollack (.NET)</author>
public class ErrorCodes
{
#region Fields
private string[] databaseProductNames;
private string[] badSqlGrammarCodes = new String[0];
private string[] invalidResultSetAccessCodes = new String[0];
private string[] duplicateKeyCodes = new string[0];
private string[] dataIntegrityViolationCodes = new String[0];
private string[] permissionDeniedCodes = new String[0];
private string[] dataAccessResourceFailureCodes = new String[0];
private string[] transientAccessResourceFailureCodes = new String[0];
private string[] cannotAcquireLockCodes = new String[0];
private string[] deadlockLoserCodes = new String[0];
private string[] cannotSerializeTransactionCodes = new String[0];
// CustomErrorCodesTranslation[] customTranslations;
#endregion
#region Constants
/// <summary>
/// The shared log instance for this class (and derived classes).
/// </summary>
protected static readonly ILog log =
LogManager.GetLogger(typeof (ErrorCodes));
#endregion
#region Constructor (s)
/// <summary>
/// Initializes a new instance of the <see cref="ErrorCodes"/> class.
/// </summary>
public ErrorCodes()
{
}
#endregion
#region Properties
public string DatabaseProductName
{
get
{
return (databaseProductNames != null && databaseProductNames.Length > 0 ?
databaseProductNames[0] : null);
}
}
public string[] DatabaseProductNames
{
get { return databaseProductNames; }
set { databaseProductNames = value; }
}
public string[] BadSqlGrammarCodes
{
get { return badSqlGrammarCodes; }
set { badSqlGrammarCodes = value; }
}
public string[] InvalidResultSetAccessCodes
{
get { return invalidResultSetAccessCodes; }
set { invalidResultSetAccessCodes = value; }
}
public string[] DataAccessResourceFailureCodes
{
get { return dataAccessResourceFailureCodes; }
set { dataAccessResourceFailureCodes = value; }
}
public string[] PermissionDeniedCodes
{
get { return permissionDeniedCodes; }
set { permissionDeniedCodes = value; }
}
public string[] DataIntegrityViolationCodes
{
get { return dataIntegrityViolationCodes; }
set { dataIntegrityViolationCodes = value; }
}
public string[] CannotAcquireLockCodes
{
get { return cannotAcquireLockCodes; }
set { cannotAcquireLockCodes = value; }
}
public string[] TransientAccessResourceFailureCodes
{
get { return transientAccessResourceFailureCodes; }
set { transientAccessResourceFailureCodes = value; }
}
public string[] DeadlockLoserCodes
{
get { return deadlockLoserCodes; }
set { deadlockLoserCodes = value; }
}
public string[] CannotSerializeTransactionCodes
{
get { return cannotSerializeTransactionCodes; }
set { cannotSerializeTransactionCodes = value; }
}
public string[] DuplicateKeyCodes
{
get { return duplicateKeyCodes; }
set { duplicateKeyCodes = value; }
}
#endregion
}
}
#endregion
}
}

View File

@@ -837,14 +837,20 @@
<!-- error codes taken from http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=/rzala/rzalaco.htm and
from Spring.Java sql-error-codes.xml -->
<property name="ErrorCodes.badSqlGrammarCodes">
<property name="ErrorCodes.BadSqlGrammarCodes">
<value>-007,-029,-097,-104,-109,-115,-128,-199,-204,-206,-301,-408,-441,-491</value>
</property>
<property name="ErrorCodes.DuplicateKeyCodes">
<value>-803</value>
</property>
<property name="ErrorCodes.DataIntegrityViolationCodes">
<value>-407,-530,-531,-532,-543,-544,-545,-603,-667,-803</value>
</property>
<property name="ErrorCodes.DataAccessResourceFailureCodes">
<value>-904,-971</value>
</property>
<property name="ErrorCodes.DataIntegrityViolationCodes">
<value>-407,-530,-531,-532,-543,-544,-545,-603,-667,-803</value>
<property name="ErrorCodes.TransientDataAccessResourceCodes">
<value>-1035,-1218,-30080,-30081</value>
</property>
<property name="ErrorCodes.DeadlockLoserCodes">
<value>-911,-913</value>
@@ -879,14 +885,20 @@
<!-- error codes taken from http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=/rzala/rzalaco.htm and
from Spring.Java sql-error-codes.xml -->
<property name="ErrorCodes.badSqlGrammarCodes">
<property name="ErrorCodes.BadSqlGrammarCodes">
<value>-007,-029,-097,-104,-109,-115,-128,-199,-204,-206,-301,-408,-441,-491</value>
</property>
<property name="ErrorCodes.DuplicateKeyCodes">
<value>-803</value>
</property>
<property name="ErrorCodes.DataIntegrityViolationCodes">
<value>-407,-530,-531,-532,-543,-544,-545,-603,-667,-803</value>
</property>
<property name="ErrorCodes.DataAccessResourceFailureCodes">
<value>-904,-971</value>
</property>
<property name="ErrorCodes.DataIntegrityViolationCodes">
<value>-407,-530,-531,-532,-543,-544,-545,-603,-667,-803</value>
<property name="ErrorCodes.TransientDataAccessResourceCodes">
<value>-1035,-1218,-30080,-30081</value>
</property>
<property name="ErrorCodes.DeadlockLoserCodes">
<value>-911,-913</value>
@@ -923,14 +935,21 @@
<!-- error codes taken from http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=/rzala/rzalaco.htm and
from Spring.Java sql-error-codes.xml -->
<property name="ErrorCodes.badSqlGrammarCodes">
<property name="ErrorCodes.BadSqlGrammarCodes">
<value>-007,-029,-097,-104,-109,-115,-128,-199,-204,-206,-301,-408,-441,-491</value>
</property>
<property name="ErrorCodes.DuplicateKeyCodes">
<value>-803</value>
</property>
<property name="ErrorCodes.DataIntegrityViolationCodes">
<value>-407,-530,-531,-532,-543,-544,-545,-603,-667,-803</value>
</property>
<property name="ErrorCodes.DataAccessResourceFailureCodes">
<value>-904,-971</value>
</property>
<property name="ErrorCodes.DataIntegrityViolationCodes">
<value>-407,-530,-531,-532,-543,-544,-545,-603,-667,-803</value>
<property name="ErrorCodes.TransientDataAccessResourceCodes">
<value>-1035,-1218,-30080,-30081</value>
</property>
<property name="ErrorCodes.DeadlockLoserCodes">
<value>-911,-913</value>
@@ -964,15 +983,22 @@
<constructor-arg name="errorCodeExceptionExpression" value="Errors[0].NativeError"/>
<!-- error codes taken from http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=/rzala/rzalaco.htm and
from Spring.Java sql-error-codes.xml -->
<property name="ErrorCodes.badSqlGrammarCodes">
<property name="ErrorCodes.BadSqlGrammarCodes">
<value>-007,-029,-097,-104,-109,-115,-128,-199,-204,-206,-301,-408,-441,-491</value>
</property>
<property name="ErrorCodes.DuplicateKeyCodes">
<value>-803</value>
</property>
<property name="ErrorCodes.DataIntegrityViolationCodes">
<value>-407,-530,-531,-532,-543,-544,-545,-603,-667,-803</value>
</property>
<property name="ErrorCodes.DataAccessResourceFailureCodes">
<value>-904,-971</value>
</property>
<property name="ErrorCodes.DataIntegrityViolationCodes">
<value>-407,-530,-531,-532,-543,-544,-545,-603,-667,-803</value>
<property name="ErrorCodes.TransientDataAccessResourceCodes">
<value>-1035,-1218,-30080,-30081</value>
</property>
<property name="ErrorCodes.DeadlockLoserCodes">
<value>-911,-913</value>
@@ -1010,14 +1036,21 @@
<!-- error codes taken from http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=/rzala/rzalaco.htm and
from Spring.Java sql-error-codes.xml -->
<property name="ErrorCodes.badSqlGrammarCodes">
<property name="ErrorCodes.BadSqlGrammarCodes">
<value>-007,-029,-097,-104,-109,-115,-128,-199,-204,-206,-301,-408,-441,-491</value>
</property>
<property name="ErrorCodes.DuplicateKeyCodes">
<value>-803</value>
</property>
<property name="ErrorCodes.DataIntegrityViolationCodes">
<value>-407,-530,-531,-532,-543,-544,-545,-603,-667,-803</value>
</property>
<property name="ErrorCodes.DataAccessResourceFailureCodes">
<value>-904,-971</value>
</property>
<property name="ErrorCodes.DataIntegrityViolationCodes">
<value>-407,-530,-531,-532,-543,-544,-545,-603,-667,-803</value>
<property name="ErrorCodes.TransientDataAccessResourceCodes">
<value>-1035,-1218,-30080,-30081</value>
</property>
<property name="ErrorCodes.DeadlockLoserCodes">
<value>-911,-913</value>
@@ -1241,6 +1274,9 @@
<property name="ErrorCodes.DataIntegrityViolationCodes">
<value>423,511,515,530,547,2601,2615,2714</value>
</property>
<property name="ErrorCodes.TransientDataAccessResourceCodes">
<value>921,1105</value>
</property>
<property name="ErrorCodes.DeadlockLoserCodes">
<value>1205</value>
</property>
@@ -1276,6 +1312,12 @@
<property name="ErrorCodes.DataIntegrityViolationCodes">
<value>423,511,515,530,547,2601,2615,2714</value>
</property>
<property name="ErrorCodes.TransientDataAccessResourceCodes">
<value>921,1105</value>
</property>
<property name="ErrorCodes.TransientDataAccessResourceCodes">
<value>921,1105</value>
</property>
<property name="ErrorCodes.DeadlockLoserCodes">
<value>1205</value>
</property>
@@ -1313,6 +1355,9 @@
<property name="ErrorCodes.DataIntegrityViolationCodes">
<value>423,511,515,530,547,2601,2615,2714</value>
</property>
<property name="ErrorCodes.TransientDataAccessResourceCodes">
<value>921,1105</value>
</property>
<property name="ErrorCodes.DeadlockLoserCodes">
<value>1205</value>
</property>

View File

@@ -1,158 +1,158 @@
#region License
/*
* Copyright <20> 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
#region Imports
using System;
using Common.Logging;
using Spring.Dao;
using Spring.Data.Common;
#endregion
namespace Spring.Data.Support
{
/// <summary>
/// Implementation of IAdoExceptionTranslator that analyzes provider specific
/// error codes and translates into the DAO exception hierarchy.
/// </summary>
/// <remarks>This class loads the obtains error codes from
/// the IDbProvider metadata property ErrorCodes
/// which defines error code mappings for various providers.
/// </remarks>
/// <author>Mark Pollack (.NET)</author>
public class ErrorCodeExceptionTranslator : IAdoExceptionTranslator
{
#region Fields
private ErrorCodes errorCodes;
private IAdoExceptionTranslator fallbackTranslator;
private IDbProvider dbProvider;
#endregion
#region Constants
/// <summary>
/// The shared log instance for this class (and derived classes).
/// </summary>
protected static readonly ILog log =
LogManager.GetLogger(typeof (ErrorCodeExceptionTranslator));
#endregion
#region Constructor (s)
/// <summary>
/// Initializes a new instance of the <see cref="ErrorCodeExceptionTranslator"/> class.
/// </summary>
/// <param name="provider">The data provider.</param>
public ErrorCodeExceptionTranslator(IDbProvider provider)
{
DbProvider = provider;
}
/// <summary>
/// Initializes a new instance of the <see cref="ErrorCodeExceptionTranslator"/> class.
/// </summary>
/// <param name="provider">The data provider.</param>
/// <param name="ec">The error code collection.</param>
public ErrorCodeExceptionTranslator(IDbProvider provider, ErrorCodes ec)
{
DbProvider = provider;
errorCodes = ec;
}
#endregion
#region Properties
/// <summary>
/// Sets the db provider.
/// </summary>
/// <value>The db provider.</value>
public IDbProvider DbProvider
{
set
{
dbProvider = value;
fallbackTranslator = new FallbackExceptionTranslator();
errorCodes = dbProvider.DbMetadata.ErrorCodes;
}
}
/// <summary>
/// Gets the error codes for the provider
/// </summary>
/// <value>The error codes.</value>
public ErrorCodes ErrorCodes
{
get
{
return errorCodes;
}
}
#endregion
/// <summary>
/// Gets or sets the fallback translator to use in case error code based translation
/// fails.
/// </summary>
/// <value>The fallback translator.</value>
public IAdoExceptionTranslator FallbackTranslator
{
get
{
return fallbackTranslator;
}
set
{
fallbackTranslator = value;
}
}
#region Methods
#endregion
/// <summary>
/// Translate the given <see cref="System.SystemException"/> into a generic data access exception.
/// </summary>
/// <param name="task">A readable string describing the task being attempted.</param>
/// <param name="sql">The SQL query or update that caused the problem. May be null.</param>
/// <param name="exception">
/// The <see cref="System.Exception"/> encountered by the ADO.NET implementation.
/// </param>
/// <returns>
/// A <see cref="Spring.Dao.DataAccessException"/> appropriate for the supplied
/// <paramref name="exception"/>.
#region License
/*
* Copyright <20> 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
#region Imports
using System;
using Common.Logging;
using Spring.Dao;
using Spring.Data.Common;
#endregion
namespace Spring.Data.Support
{
/// <summary>
/// Implementation of IAdoExceptionTranslator that analyzes provider specific
/// error codes and translates into the DAO exception hierarchy.
/// </summary>
/// <remarks>This class loads the obtains error codes from
/// the IDbProvider metadata property ErrorCodes
/// which defines error code mappings for various providers.
/// </remarks>
/// <author>Mark Pollack (.NET)</author>
public class ErrorCodeExceptionTranslator : IAdoExceptionTranslator
{
#region Fields
private ErrorCodes errorCodes;
private IAdoExceptionTranslator fallbackTranslator;
private IDbProvider dbProvider;
#endregion
#region Constants
/// <summary>
/// The shared log instance for this class (and derived classes).
/// </summary>
protected static readonly ILog log =
LogManager.GetLogger(typeof (ErrorCodeExceptionTranslator));
#endregion
#region Constructor (s)
/// <summary>
/// Initializes a new instance of the <see cref="ErrorCodeExceptionTranslator"/> class.
/// </summary>
/// <param name="provider">The data provider.</param>
public ErrorCodeExceptionTranslator(IDbProvider provider)
{
DbProvider = provider;
}
/// <summary>
/// Initializes a new instance of the <see cref="ErrorCodeExceptionTranslator"/> class.
/// </summary>
/// <param name="provider">The data provider.</param>
/// <param name="ec">The error code collection.</param>
public ErrorCodeExceptionTranslator(IDbProvider provider, ErrorCodes ec)
{
DbProvider = provider;
errorCodes = ec;
}
#endregion
#region Properties
/// <summary>
/// Sets the db provider.
/// </summary>
/// <value>The db provider.</value>
public IDbProvider DbProvider
{
set
{
dbProvider = value;
fallbackTranslator = new FallbackExceptionTranslator();
errorCodes = dbProvider.DbMetadata.ErrorCodes;
}
}
/// <summary>
/// Gets the error codes for the provider
/// </summary>
/// <value>The error codes.</value>
public ErrorCodes ErrorCodes
{
get
{
return errorCodes;
}
}
#endregion
/// <summary>
/// Gets or sets the fallback translator to use in case error code based translation
/// fails.
/// </summary>
/// <value>The fallback translator.</value>
public IAdoExceptionTranslator FallbackTranslator
{
get
{
return fallbackTranslator;
}
set
{
fallbackTranslator = value;
}
}
#region Methods
#endregion
/// <summary>
/// Translate the given <see cref="System.SystemException"/> into a generic data access exception.
/// </summary>
/// <param name="task">A readable string describing the task being attempted.</param>
/// <param name="sql">The SQL query or update that caused the problem. May be null.</param>
/// <param name="exception">
/// The <see cref="System.Exception"/> encountered by the ADO.NET implementation.
/// </param>
/// <returns>
/// A <see cref="Spring.Dao.DataAccessException"/> appropriate for the supplied
/// <paramref name="exception"/>.
/// </returns>
public virtual DataAccessException Translate(string task, string sql, Exception exception)
{
@@ -206,139 +206,144 @@ namespace Spring.Data.Support
/// return <code>null</code> to indicate that no exception match has been found and that
/// fallback translation should kick in.
/// </remarks>
protected virtual DataAccessException DoTranslate(string task, string sql, string errorCode, Exception exception)
{
// First, try custom translation from overridden method.
DataAccessException dex = TranslateException(task, sql, errorCode, exception);
if (dex != null)
{
return dex;
}
if (errorCodes != null)
{
if (errorCode != null)
{
if (Array.IndexOf(errorCodes.BadSqlGrammarCodes, errorCode) >= 0)
{
LogTranslation(task, sql, errorCode, exception, false);
return new BadSqlGrammarException(task, sql, exception);
}
else if (Array.IndexOf(errorCodes.InvalidResultSetAccessCodes, errorCode) >= 0)
{
LogTranslation(task, sql, errorCode, exception, false);
return new InvalidResultSetAccessException(task, sql, exception);
protected virtual DataAccessException DoTranslate(string task, string sql, string errorCode, Exception exception)
{
// First, try custom translation from overridden method.
DataAccessException dex = TranslateException(task, sql, errorCode, exception);
if (dex != null)
{
return dex;
}
if (errorCodes != null)
{
if (errorCode != null)
{
if (Array.IndexOf(errorCodes.BadSqlGrammarCodes, errorCode) >= 0)
{
LogTranslation(task, sql, errorCode, exception, false);
return new BadSqlGrammarException(task, sql, exception);
}
else if (Array.IndexOf(errorCodes.InvalidResultSetAccessCodes, errorCode) >= 0)
{
LogTranslation(task, sql, errorCode, exception, false);
return new InvalidResultSetAccessException(task, sql, exception);
}
else if (Array.IndexOf(errorCodes.DuplicateKeyCodes, errorCode) >= 0)
{
LogTranslation(task, sql, errorCode, exception, false);
return new DuplicateKeyException(task, sql, exception);
}
else if (Array.IndexOf(errorCodes.DataAccessResourceFailureCodes, errorCode) >= 0)
{
LogTranslation(task, sql, errorCode, exception, false);
return new DataAccessResourceFailureException(BuildMessage(task, sql, exception), exception);
}
else if (Array.IndexOf(errorCodes.PermissionDeniedCodes, errorCode) >= 0)
{
LogTranslation(task, sql, errorCode, exception, false);
return new PermissionDeniedDataAccessException(BuildMessage(task, sql, exception), exception);
}
else if (Array.IndexOf(errorCodes.DataIntegrityViolationCodes, errorCode) >= 0)
{
LogTranslation(task, sql, errorCode, exception, false);
return new DataIntegrityViolationException(BuildMessage(task, sql, exception), exception);
}
else if (Array.IndexOf(errorCodes.CannotAcquireLockCodes, errorCode) >= 0)
{
LogTranslation(task, sql, errorCode, exception, false);
return new CannotAcquireLockException(BuildMessage(task, sql, exception), exception);
}
else if (Array.IndexOf(errorCodes.DeadlockLoserCodes, errorCode) >= 0)
{
LogTranslation(task, sql, errorCode, exception, false);
return new DeadlockLoserDataAccessException(BuildMessage(task, sql, exception), exception);
}
else if (Array.IndexOf(errorCodes.CannotSerializeTransactionCodes, errorCode) >= 0)
{
LogTranslation(task, sql, errorCode, exception, false);
return new CannotSerializeTransactionException(BuildMessage(task, sql, exception), exception);
}
}
}
return null;
}
/// <summary>
/// Subclasses can override this method to attempt a custom mapping from a data access Exception
/// to DataAccessException.
/// </summary>
/// <param name="task">Readable text describing the task being attempted.</param>
/// <param name="sql">SQL query or update that caused the problem. May be <code>null</code>.</param>
/// <param name="errorCode">The error code extracted from the generic data access exception for
/// a particular provider.</param>
/// <param name="exception">The exception thrown from a data access operation.</param>
/// <returns>
/// null if no custom translation was possible, otherwise a DataAccessException
/// resulting from custom translation. This exception should include the exception parameter
/// as a nested root cause. This implementation always returns null, meaning that
/// the translator always falls back to the default error codes.
/// </returns>
protected virtual DataAccessException TranslateException(string task, string sql, string errorCode, Exception exception)
{
return null;
}
/// <summary>
/// Builds the message.
/// </summary>
/// <param name="task">The task.</param>
/// <param name="sql">The SQL.</param>
/// <param name="exception">The exception.</param>
/// <returns></returns>
protected virtual string BuildMessage(string task, string sql, Exception exception)
{
return task + "; SQL [" + sql + "]; " + exception.Message;
}
/// <summary>
/// Determines whether the specified exception is valid data access exception.
/// </summary>
/// <param name="e">The exception.</param>
/// <returns>
/// <c>true</c> if is valid data access exception; otherwise, <c>false</c>.
/// </returns>
public bool IsValidDataAccessException(Exception e)
{
return dbProvider.IsDataAccessException(e);
}
/// <summary>
/// Logs the translation.
/// </summary>
/// <param name="task">The task.</param>
/// <param name="sql">The SQL.</param>
/// <param name="errorCode">The error code.</param>
/// <param name="exception">The exception.</param>
/// <param name="b">if set to <c>true</c> [b].</param>
private void LogTranslation(string task, string sql, string errorCode, Exception exception, bool b)
{
if (log.IsDebugEnabled)
{
String intro = "Translating";
log.Debug(intro + " ADO exception with error code '" + errorCode
+ "', message [" + exception.Message +
"]; SQL was [" + sql + "] for task [" + task + "]");
}
}
private string ExtractErrorCode(Exception exception)
{
// Use provider specific reflection information to extract error code.
return dbProvider.ExtractError(exception);
}
}
}
}
else if (Array.IndexOf(errorCodes.DataAccessResourceFailureCodes, errorCode) >= 0)
{
LogTranslation(task, sql, errorCode, exception, false);
return new DataAccessResourceFailureException(BuildMessage(task, sql, exception), exception);
}
else if (Array.IndexOf(errorCodes.TransientAccessResourceFailureCodes, errorCode) >= 0)
{
LogTranslation(task, sql, errorCode, exception, false);
return new TransientDataAccessResourceException(BuildMessage(task, sql, exception), exception);
}
else if (Array.IndexOf(errorCodes.PermissionDeniedCodes, errorCode) >= 0)
{
LogTranslation(task, sql, errorCode, exception, false);
return new PermissionDeniedDataAccessException(BuildMessage(task, sql, exception), exception);
}
else if (Array.IndexOf(errorCodes.DataIntegrityViolationCodes, errorCode) >= 0)
{
LogTranslation(task, sql, errorCode, exception, false);
return new DataIntegrityViolationException(BuildMessage(task, sql, exception), exception);
}
else if (Array.IndexOf(errorCodes.CannotAcquireLockCodes, errorCode) >= 0)
{
LogTranslation(task, sql, errorCode, exception, false);
return new CannotAcquireLockException(BuildMessage(task, sql, exception), exception);
}
else if (Array.IndexOf(errorCodes.DeadlockLoserCodes, errorCode) >= 0)
{
LogTranslation(task, sql, errorCode, exception, false);
return new DeadlockLoserDataAccessException(BuildMessage(task, sql, exception), exception);
}
else if (Array.IndexOf(errorCodes.CannotSerializeTransactionCodes, errorCode) >= 0)
{
LogTranslation(task, sql, errorCode, exception, false);
return new CannotSerializeTransactionException(BuildMessage(task, sql, exception), exception);
}
}
}
return null;
}
/// <summary>
/// Subclasses can override this method to attempt a custom mapping from a data access Exception
/// to DataAccessException.
/// </summary>
/// <param name="task">Readable text describing the task being attempted.</param>
/// <param name="sql">SQL query or update that caused the problem. May be <code>null</code>.</param>
/// <param name="errorCode">The error code extracted from the generic data access exception for
/// a particular provider.</param>
/// <param name="exception">The exception thrown from a data access operation.</param>
/// <returns>
/// null if no custom translation was possible, otherwise a DataAccessException
/// resulting from custom translation. This exception should include the exception parameter
/// as a nested root cause. This implementation always returns null, meaning that
/// the translator always falls back to the default error codes.
/// </returns>
protected virtual DataAccessException TranslateException(string task, string sql, string errorCode, Exception exception)
{
return null;
}
/// <summary>
/// Builds the message.
/// </summary>
/// <param name="task">The task.</param>
/// <param name="sql">The SQL.</param>
/// <param name="exception">The exception.</param>
/// <returns></returns>
protected virtual string BuildMessage(string task, string sql, Exception exception)
{
return task + "; SQL [" + sql + "]; " + exception.Message;
}
/// <summary>
/// Determines whether the specified exception is valid data access exception.
/// </summary>
/// <param name="e">The exception.</param>
/// <returns>
/// <c>true</c> if is valid data access exception; otherwise, <c>false</c>.
/// </returns>
public bool IsValidDataAccessException(Exception e)
{
return dbProvider.IsDataAccessException(e);
}
/// <summary>
/// Logs the translation.
/// </summary>
/// <param name="task">The task.</param>
/// <param name="sql">The SQL.</param>
/// <param name="errorCode">The error code.</param>
/// <param name="exception">The exception.</param>
/// <param name="b">if set to <c>true</c> [b].</param>
private void LogTranslation(string task, string sql, string errorCode, Exception exception, bool b)
{
if (log.IsDebugEnabled)
{
String intro = "Translating";
log.Debug(intro + " ADO exception with error code '" + errorCode
+ "', message [" + exception.Message +
"]; SQL was [" + sql + "] for task [" + task + "]");
}
}
private string ExtractErrorCode(Exception exception)
{
// Use provider specific reflection information to extract error code.
return dbProvider.ExtractError(exception);
}
}
}

View File

@@ -1,7 +1,7 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<ProjectType>Local</ProjectType>
<ProductVersion>9.0.30729</ProductVersion>
<ProductVersion>9.0.21022</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{AE00E5AB-C39A-436F-86D2-33BFE33E2E40}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -104,6 +104,8 @@
<Compile Include="Dao\CannotSerializeTransactionException.cs" />
<Compile Include="Dao\CleanupFailureDataAccessException.cs" />
<Compile Include="Dao\ConcurrencyFailureException.cs" />
<Compile Include="Dao\TransientDataAccessResourceException.cs" />
<Compile Include="Dao\TransientDataAccessException.cs" />
<Compile Include="Dao\PessimisticLockingFailureException.cs" />
<Compile Include="Dao\DataAccessException.cs" />
<Compile Include="Dao\DataAccessResourceFailureException.cs" />