blob: 8d93564105b9f92faeea87aa7b88055baa817b1e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using Apache.NMS;
using Amqp.Framing;
using Amqp;
namespace Apache.NMS.AMQP.Util
{
class ExceptionSupport
{
private static readonly Dictionary<string, Type> errTypeMap;
static ExceptionSupport()
{
// mapping of amqp .Net Lite error code to NMS exception type
errTypeMap = new Dictionary<string, Type>();
errTypeMap.Add(NMSErrorCode.CONNECTION_TIME_OUT, typeof(NMSConnectionException));
errTypeMap.Add(ErrorCode.ConnectionRedirect, typeof(NMSConnectionException));
errTypeMap.Add(ErrorCode.ConnectionForced, typeof(NMSConnectionException));
errTypeMap.Add(ErrorCode.IllegalState, typeof(IllegalStateException));
errTypeMap.Add(NMSErrorCode.INTERNAL_ERROR, typeof(NMSException));
errTypeMap.Add(NMSErrorCode.UNKNOWN_ERROR, typeof(NMSException));
errTypeMap.Add(NMSErrorCode.SESSION_TIME_OUT, typeof(NMSException));
errTypeMap.Add(NMSErrorCode.LINK_TIME_OUT, typeof(NMSException));
errTypeMap.Add(ErrorCode.DecodeError, typeof(NMSException));
errTypeMap.Add(ErrorCode.DetachForced, typeof(NMSException));
errTypeMap.Add(ErrorCode.ErrantLink, typeof(NMSException));
errTypeMap.Add(ErrorCode.FrameSizeTooSmall, typeof(NMSConnectionException));
errTypeMap.Add(ErrorCode.FramingError, typeof(NMSConnectionException));
errTypeMap.Add(ErrorCode.HandleInUse, typeof(NMSException));
errTypeMap.Add(ErrorCode.InternalError, typeof(NMSException));
errTypeMap.Add(ErrorCode.InvalidField, typeof(NMSException));
errTypeMap.Add(ErrorCode.LinkRedirect, typeof(NMSException));
errTypeMap.Add(ErrorCode.MessageReleased, typeof(IllegalStateException));
errTypeMap.Add(ErrorCode.MessageSizeExceeded, typeof(NMSException));
errTypeMap.Add(ErrorCode.NotAllowed, typeof(NMSException));
errTypeMap.Add(ErrorCode.NotFound, typeof(InvalidDestinationException));
errTypeMap.Add(ErrorCode.NotImplemented, typeof(NMSException));
errTypeMap.Add(ErrorCode.PreconditionFailed, typeof(NMSException));
errTypeMap.Add(ErrorCode.ResourceDeleted, typeof(NMSException));
errTypeMap.Add(ErrorCode.ResourceLimitExceeded, typeof(NMSException));
errTypeMap.Add(ErrorCode.ResourceLocked, typeof(NMSException));
errTypeMap.Add(ErrorCode.Stolen, typeof(NMSException));
errTypeMap.Add(ErrorCode.TransactionRollback, typeof(TransactionRolledBackException));
errTypeMap.Add(ErrorCode.TransactionTimeout, typeof(TransactionInProgressException));
errTypeMap.Add(ErrorCode.TransactionUnknownId, typeof(TransactionRolledBackException));
errTypeMap.Add(ErrorCode.TransferLimitExceeded, typeof(NMSException));
errTypeMap.Add(ErrorCode.UnattachedHandle, typeof(NMSException));
errTypeMap.Add(ErrorCode.UnauthorizedAccess, typeof(NMSSecurityException));
errTypeMap.Add(ErrorCode.WindowViolation, typeof(NMSException));
}
private static FieldInfo[] GetConstants(Type type)
{
ArrayList list = new ArrayList();
FieldInfo[] fields = type.GetFields(
BindingFlags.Static |
BindingFlags.Public |
BindingFlags.FlattenHierarchy
);
foreach (FieldInfo field in fields)
{
if (field.IsLiteral && !field.IsInitOnly)
list.Add(field);
}
return (FieldInfo[])list.ToArray(typeof(FieldInfo));
}
private static string[] GetStringConstants(Type type)
{
FieldInfo[] fields = GetConstants(type);
ArrayList list = new ArrayList(fields.Length);
foreach(FieldInfo fi in fields)
{
if (fi.FieldType.Equals(typeof(string)))
{
list.Add(fi.GetValue(null));
}
}
return (string[])list.ToArray(typeof(string));
}
public static NMSException GetTimeoutException(IAmqpObject obj, string format, params object[] args)
{
return GetTimeoutException(obj, string.Format(format, args));
}
public static NMSException GetTimeoutException(IAmqpObject obj, string message)
{
Error e = null;
if (obj is Amqp.Connection)
{
e = NMSError.CONNECTION_TIMEOUT;
}
else if (obj is Amqp.Session)
{
e = NMSError.SESSION_TIMEOUT;
}
else if (obj is Amqp.Link)
{
e = NMSError.LINK_TIMEOUT;
}
return GetException(e, message);
}
public static NMSException GetException(IAmqpObject obj, string format, params object[] args)
{
return GetException(obj, string.Format(format, args));
}
public static NMSException GetException(Error amqpErr, string format, params object[] args)
{
return GetException(amqpErr, string.Format(format, args));
}
public static NMSException GetException(IAmqpObject obj, string message="")
{
return GetException(obj.Error, message);
}
public static NMSException GetException(Error amqpErr, string message = "", Exception e = null)
{
string errCode = null;
string errMessage = null;
string additionalErrInfo = null;
if (amqpErr == null)
{
amqpErr = NMSError.INTERNAL;
}
errCode = amqpErr.Condition.ToString();
errMessage = amqpErr.Description;
errMessage = errMessage != null ? ", Description = " + errMessage : "";
if (amqpErr.Info != null && amqpErr.Info.Count > 0)
{
additionalErrInfo = ", ErrorInfo = " + Types.ConversionSupport.ToString(amqpErr.Info);
}
if (null == e)
{
// no exception given, create a NMSunthrownException to hold the
// stack and use it as the innerException in the constructors for
// the NMSexception we create., the custom StackTrace() will allow exception listeners to
// see the stack to here
e = new NMSProviderError(errCode, errMessage);
}
NMSException ex = null;
Type exType = null;
if(errTypeMap.TryGetValue(errCode, out exType))
{
ConstructorInfo ci = exType.GetConstructor(new[] { typeof(string), typeof(string), typeof(Exception) });
object inst = ci.Invoke(new object[] { message + errMessage + additionalErrInfo , errCode, e });
ex = inst as NMSException;
}
else
{
ex = new NMSException(message + errMessage + additionalErrInfo, errCode, e);
}
return ex;
}
public static NMSException Wrap(Exception e, string format, params object[] args)
{
return Wrap(e, string.Format(format, args));
}
public static NMSException Wrap(Exception e, string message = "")
{
if(e == null)
{
return null;
}
NMSException nmsEx = null;
string exMessage = message;
if (exMessage == null || exMessage.Length == 0)
{
exMessage = e.Message;
}
if (e is NMSException)
{
return e as NMSException;
}
else if (e is AmqpException)
{
Error err = (e as AmqpException).Error;
nmsEx = GetException(err, message, e);
Tracer.DebugFormat("Encoutered AmqpException {0} and created NMS Exception {1}.", e, nmsEx);
}
else
{
nmsEx = new NMSException(exMessage, NMSErrorCode.INTERNAL_ERROR, e);
}
return nmsEx;
}
}
#region Exceptions
public class InvalidPropertyException : NMSException
{
protected static string ExFormat = "Invalid Property {0}. Cause: {1}";
public InvalidPropertyException(string property, string message) : base(string.Format(ExFormat, property, message))
{
exceptionErrorCode = NMSErrorCode.PROPERTY_ERROR;
}
}
// The API converts AMPQ Errors to NMSProviderError. This is typically added to
// the Exception queue and passed to the ExceptionListener. As the Exception is
// instantiated but never thrown, it does not have an exception-stack trace. We add
// one to the private member InstanceTrace and override StackTrace so useful
// information can be displayed.
internal class NMSProviderError : NMSException
{
private string InstanceTrace;
public NMSProviderError() : base()
{
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(1, true);
InstanceTrace = trace.ToString();
}
public NMSProviderError(string message) : base(message)
{
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(1, true);
InstanceTrace = trace.ToString();
}
public NMSProviderError(string message, string errorCode) : base(message, errorCode)
{
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(1, true);
InstanceTrace = trace.ToString();
}
public NMSProviderError(string message, NMSException innerException) : base(message, innerException)
{
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(1, true);
InstanceTrace = trace.ToString();
exceptionErrorCode = innerException.ErrorCode ?? NMSErrorCode.INTERNAL_ERROR;
}
public NMSProviderError(string message, Exception innerException) : base(message, innerException)
{
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(1, true);
InstanceTrace = trace.ToString();
}
public NMSProviderError(string message, string errorCode, Exception innerException) : base(message, errorCode, innerException)
{
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(1, true);
InstanceTrace = trace.ToString();
}
public override string StackTrace
{
get
{
string stack = base.StackTrace;
if (stack == null || stack.Length == 0)
{
stack = InstanceTrace;
}
if (InnerException != null && (InnerException.StackTrace != null && InnerException.StackTrace.Length > 0))
{
stack += "\nCause " + InnerException.Message + " : \n" +
InnerException.StackTrace;
}
return stack;
}
}
}
#endregion
#region Error Codes
internal static class NMSError
{
public static Error SESSION_TIMEOUT = new Error(NMSErrorCode.SESSION_TIME_OUT) { Description = "Session Begin Request has timed out." };
public static Error CONNECTION_TIMEOUT = new Error(NMSErrorCode.SESSION_TIME_OUT) { Description = "Connection Open Request has timed out." };
public static Error LINK_TIMEOUT = new Error(NMSErrorCode.SESSION_TIME_OUT) { Description = "Link Attach Request has timed out." };
public static Error PROPERTY = new Error(NMSErrorCode.PROPERTY_ERROR) { Description = "Property Error." };
public static Error UNKNOWN = new Error(NMSErrorCode.UNKNOWN_ERROR) { Description = "Unknown Error." };
public static Error INTERNAL = new Error(NMSErrorCode.INTERNAL_ERROR) { Description = "Internal Error." };
}
internal static class NMSErrorCode
{
public static string CONNECTION_TIME_OUT = "nms:connection:timout";
public static string SESSION_TIME_OUT = "nms:session:timout";
public static string LINK_TIME_OUT = "nms:link:timeout";
public static string PROPERTY_ERROR = "nms:property:error";
public static string UNKNOWN_ERROR = "nms:unknown";
public static string INTERNAL_ERROR = "nms:internal";
}
#endregion
}