blob: 273b4149a0c07f551776355759b1e200000d4f18 [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;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Amqp.Types;
using Amqp;
using Apache.NMS;
namespace Apache.NMS.AMQP.Util.Types
{
internal static class ConversionSupport
{
public static Amqp.Types.Map NMSMapToAmqp(IPrimitiveMap nmsmap)
{
if(nmsmap == null) return null;
Amqp.Types.Map result = new Amqp.Types.Map();
if(nmsmap is Map.AMQP.AMQPValueMap) { return (nmsmap as Map.AMQP.AMQPValueMap).AmqpMap; }
else
{
foreach (string key in nmsmap.Keys)
{
object value = nmsmap[key];
if (value is IDictionary)
{
value = ConversionSupport.MapToAmqp(value as IDictionary);
}
else if (value is IList)
{
value = ConversionSupport.ListToAmqp(value as IList);
}
result[key] = value;
//Tracer.InfoFormat("Conversion key : {0}, value : {1}, valueType: {2} nmsValue: {3}, nmsValueType: {4}.",
// key, value, value.GetType().Name, );
}
}
return result;
}
public static IPrimitiveMap AmqpMapToNMS(Amqp.Types.Map map)
{
if (map == null) return null;
IPrimitiveMap result = new Map.AMQP.AMQPValueMap(map);
return result;
}
public static Amqp.Types.Map MapToAmqp(IDictionary dictionary)
{
if (dictionary == null) return null;
/*if (dictionary is Amqp.Types.Map)
{
Amqp.Types.Map DictMap = dictionary as Amqp.Types.Map;
return DictMap.Clone() as Amqp.Types.Map;
}*/
Amqp.Types.Map map = new Amqp.Types.Map();
IEnumerator iterator = dictionary.Keys.GetEnumerator();
iterator.MoveNext();
object key = iterator.Current;
if (key == null) return null;
object value = null;
do
{
value = dictionary[key];
if (value != null)
{
Type valtype = value.GetType();
if (value is IDictionary)
{
map[key] = ConversionSupport.MapToAmqp(value as IDictionary);
}
else if (value is IList)
{
map[key] = ConversionSupport.ListToAmqp(value as IList);
}
else if (IsNMSType(value))
//else if (valtype.IsPrimitive || value is byte[] || value is String)
{
map[key] = value;
}
else
{
Tracer.InfoFormat("Failed to convert IDictionary[{0}], value{1} to Map value: Invalid Type: {2}",
key, value.ToString(), valtype.Name);
}
}
}
while (iterator.MoveNext() && (key = iterator.Current) != null);
return map;
}
public static IDictionary MapToNMS(Amqp.Types.Map map)
{
if (map == null) return null;
IDictionary dictionary = new Dictionary<object, object>(map) as IDictionary;
return dictionary;
}
public static IList ListToAmqp(IList ilist)
{
if (ilist == null) return null;
//
// Special case for Byte[] which has the iList interface, we
// don't want to convert Byte[] to a List so just return a copy.
// Return a copy because it may be added to a List or Dictionary as
// a reference, which will arrive here, and we want to be sure we have
// our own copy after return.
if (ilist is Byte[])
{
byte[] copy = new byte[(ilist as Byte[]).Length];
Array.Copy(ilist as Byte[], 0, copy, 0, (ilist as Byte[]).Length);
return copy;
}
List list = new List();
foreach(object o in ilist)
{
object value = o;
if(o != null)
{
Type valtype = value.GetType();
if (value is IDictionary)
{
value = ConversionSupport.MapToAmqp(value as IDictionary);
}
else if (value is IList)
{
value = ConversionSupport.ListToAmqp(value as IList);
}
else if (ConversionSupport.IsNMSType(value))
//else if (valtype.IsPrimitive || value is byte[] || value is String)
{
// do nothing
// value = value;
}
else
{
Tracer.InfoFormat("Failed to convert IList to amqp List value({0}): Invalid Type: {1}",
value.ToString(), valtype.Name);
}
}
list.Add(value);
}
return list;
}
public static IList ListToNMS(List list)
{
if (list == null) return null;
IList ilist = new ArrayList(list);
return ilist;
}
public static string ToString(Amqp.Types.Map map)
{
if (map == null) return "{}";
string result = "{";
bool first = true;
foreach (object key in map.Keys)
{
if (first) result += "\n";
first = false;
//
// handle byte arrays for now
// add more special handlers as needed.
//
if (map[key] is byte[])
{
result += string.Format("key: {0}, len={1}, {2};\n", key.ToString(), (map[key] as byte[]).Length, BitConverter.ToString(map[key] as byte[]).Replace("-", " "));
}
else
{
result += "key: " + key.ToString() + ", value: " + map[key].ToString() + ";\n";
}
}
result += "}";
return result;
}
public static string ToString(IPrimitiveMap map)
{
if (map == null) return "{}";
string result = "{";
bool first = true;
foreach (string key in map.Keys)
{
if (first) result += "\n";
first = false;
if (map[key] is byte[])
{
result += string.Format("key: {0}, len={1}, value: {2};\n", key.ToString(), (map[key] as byte[]).Length, BitConverter.ToString(map[key] as byte[]).Replace("-", " "));
}
else
{
result += "key: " + key.ToString() + ", value: " + map[key].ToString() + ";\n";
}
}
result += "}";
return result;
}
#region NMS Type Conversion Table
static ConversionSupport(){
Dictionary < ConversionKey, ConversionEntry > typeMap = new Dictionary<ConversionKey, ConversionEntry>(NMSTypeConversionSet.Count);
foreach(ConversionEntry entry in NMSTypeConversionSet)
{
typeMap.Add(entry, entry);
}
NMSTypeConversionTable = typeMap;
}
public enum NMS_TYPE_INDEX
{
STRING = 0,
INT32 = 1,
UINT32 = 2,
INT16 = 3,
UINT16 = 4,
INT64 = 5,
UINT64 = 6,
FLOAT32 = 7,
FLOAT64 = 8,
DOUBLE = 8,
INT8 = 9,
UINT8 = 10,
CHAR = 11,
BOOLEAN = 12,
BYTE_ARRAY = 13,
NULL = 14,
OBJECT = 15,
UNKOWN
}
private static readonly Type[] NMSTypes = { typeof(String),
typeof(int), typeof(uint),
typeof(short), typeof(ushort),
typeof(long), typeof(ulong),
typeof(float), typeof(double),
typeof(sbyte), typeof(byte),
typeof(char), typeof(bool), typeof(byte[]), null, typeof(object) };
public delegate T ConversionInstance<T, K>(K o);
private class ConversionKey : IComparable
{
private int hash = 0;
internal static ConversionKey GetKey(Type target, Type Source)
{
return new ConversionKey(target, Source);
}
protected ConversionKey(Type target, Type source)
{
TargetType = target;
SourceType = source;
SetHashCode();
}
public Type TargetType { get; protected set; }
public Type SourceType { get; protected set; }
public int CompareTo(object obj)
{
if(obj != null && obj is ConversionKey) { return CompareTo(obj as ConversionKey); }
return -1;
}
protected void SetHashCode()
{
long th = TargetType.GetHashCode();
long sh = SourceType.GetHashCode();
// Cantor pairing
hash = (int)((th + sh) * (th + sh + 1) / 2 + sh);
}
protected virtual int CompareTo(ConversionKey other)
{
return other.GetHashCode() - this.GetHashCode();
}
public override bool Equals(object obj)
{
if(obj != null && obj is ConversionKey)
{
return this.CompareTo(obj as ConversionKey) == 0;
}
else
{
return base.Equals(obj);
}
}
public override int GetHashCode()
{
return hash;
}
public override string ToString()
{
return this.GetType().Name + "| SourceType: " + SourceType.Name + ", TargetType " + TargetType.Name;
}
}
private abstract class ConversionEntry : ConversionKey
{
protected ConversionEntry(Type t, Type s) : base(t,s) { }
public abstract object Convert(object o);
}
private class ConversionEntry<T, K> : ConversionEntry
{
internal ConversionInstance<T, K> ConvertInstance;
internal ConversionEntry() : base(typeof(T), typeof(K))
{
}
public override object Convert(object o)
{
if (ConvertInstance != null)
{
return ConvertInstance((K)o);
}
return null;
}
public override string ToString()
{
return base.ToString() + ", Convert Instance Delegate : " + ConvertInstance.ToString();
}
}
//public static readonly IReadOnlyDictionary<Type, IReadOnlyDictionary<Type, ConversionInstance<,object>>> NMSTypeConversionTable = new Dictionary<Type, IReadOnlyDictionary<Type, ConversionInstance<?,?>>>
//{
/* Type convert to Types convert from */
/*{ Types[Convert.ToInt32(TYPE_INDEX.STRING)], new Type[]{ typeof(string), typeof(float), typeof(double), typeof(long), typeof(int),typeof(short),typeof(byte),typeof(bool),typeof(char)} },
{ Types[Convert.ToInt32(TYPE_INDEX.DOUBLE)], new Type[]{ typeof(string), typeof(float), typeof(double)} },
{ Types[Convert.ToInt32(TYPE_INDEX.FLOAT32)], new Type[]{ typeof(string), typeof(float)} },
{ Types[Convert.ToInt32(TYPE_INDEX.INT64)], new Type[]{ typeof(string), typeof(long), typeof(int), typeof(short), typeof(byte)} },
{ Types[Convert.ToInt32(TYPE_INDEX.INT32)], new Type[]{ typeof(string), typeof(int), typeof(short), typeof(byte)} },
{ Types[Convert.ToInt32(TYPE_INDEX.INT16)], new Type[]{ typeof(string), typeof(short), typeof(byte)} },
{ Types[Convert.ToInt32(TYPE_INDEX.INT8)], new Type[]{ typeof(string), typeof(byte)} },
{ Types[Convert.ToInt32(TYPE_INDEX.CHAR)], new Type[]{ typeof(char)} },
{ Types[Convert.ToInt32(TYPE_INDEX.BOOLEAN)], new Type[]{ typeof(string), typeof(bool)} },*/
//};
#if NET40
private static readonly IDictionary<ConversionKey, ConversionEntry> NMSTypeConversionTable;
#else
private static readonly IReadOnlyDictionary<ConversionKey, ConversionEntry> NMSTypeConversionTable;
#endif
private static readonly ISet<ConversionEntry> NMSTypeConversionSet = new HashSet<ConversionEntry>
{
// string conversion
{ new ConversionEntry<string, string>{ConvertInstance = ((o) =>{ return Convert.ToString(o); }) } },
{ new ConversionEntry<string, float>{ConvertInstance = ((o) =>{ return Convert.ToString(o); }) } },
{ new ConversionEntry<string, double>{ConvertInstance = ((o) =>{ return Convert.ToString(o); }) } },
{ new ConversionEntry<string, long>{ConvertInstance = ((o) =>{ return Convert.ToString(o); }) } },
{ new ConversionEntry<string, int>{ConvertInstance = ((o) =>{ return Convert.ToString(o); }) } },
{ new ConversionEntry<string, short>{ConvertInstance = ((o) =>{ return Convert.ToString(o); }) } },
{ new ConversionEntry<string, sbyte>{ConvertInstance = ((o) =>{ return Convert.ToString(o); }) } },
{ new ConversionEntry<string, bool>{ConvertInstance = ((o) =>{ return Convert.ToString(o); }) } },
{ new ConversionEntry<string, char>{ConvertInstance = ((o) =>{ return Convert.ToString(o); }) } },
{ new ConversionEntry<string, ulong>{ConvertInstance = ((o) =>{ return Convert.ToString(o); }) } },
{ new ConversionEntry<string, uint>{ConvertInstance = ((o) =>{ return Convert.ToString(o); }) } },
{ new ConversionEntry<string, ushort>{ConvertInstance = ((o) =>{ return Convert.ToString(o); }) } },
{ new ConversionEntry<string, byte>{ConvertInstance = ((o) =>{ return Convert.ToString(o); }) } },
//{new ConversionEntry<string, byte[]>{ConvertInstance = ((o) =>{ throw new InvalidOperationException("Cannot convert string to byte array."); }) } },
// double conversion
{ new ConversionEntry<double, string>{ConvertInstance = ((o) =>{ return Convert.ToDouble(o); }) } },
{ new ConversionEntry<double, float>{ConvertInstance = ((o) =>{ return Convert.ToDouble(o); }) } },
{ new ConversionEntry<double, double>{ConvertInstance = ((o) =>{ return Convert.ToDouble(o); }) } },
// float conversion
{ new ConversionEntry<float, string>{ConvertInstance = ((o) =>{ return Convert.ToSingle(o); }) } },
{ new ConversionEntry<float, float>{ConvertInstance = ((o) =>{ return Convert.ToSingle(o); }) } },
// long conversion
{ new ConversionEntry<long, string>{ConvertInstance = ((o) =>{ return Convert.ToInt64(o); }) } },
{ new ConversionEntry<long, long>{ConvertInstance = ((o) =>{ return Convert.ToInt64(o); }) } },
{ new ConversionEntry<long, int>{ConvertInstance = ((o) =>{ return Convert.ToInt64(o); }) } },
{ new ConversionEntry<long, short>{ConvertInstance = ((o) =>{ return Convert.ToInt64(o); }) } },
{ new ConversionEntry<long, sbyte>{ConvertInstance = ((o) =>{ return Convert.ToInt64(o); }) } },
{ new ConversionEntry<long, ulong>{ConvertInstance = ((o) =>{ return Convert.ToInt64(o); }) } },
{ new ConversionEntry<long, uint>{ConvertInstance = ((o) =>{ return Convert.ToInt64(o); }) } },
{ new ConversionEntry<long, ushort>{ConvertInstance = ((o) =>{ return Convert.ToInt64(o); }) } },
{ new ConversionEntry<long, byte>{ConvertInstance = ((o) =>{ return Convert.ToInt64(o); }) } },
// int conversion
{ new ConversionEntry<int, string>{ConvertInstance = ((o) =>{ return Convert.ToInt32(o); }) } },
{ new ConversionEntry<int, int>{ConvertInstance = ((o) =>{ return Convert.ToInt32(o); }) } },
{ new ConversionEntry<int, short>{ConvertInstance = ((o) =>{ return Convert.ToInt32(o); }) } },
{ new ConversionEntry<int, sbyte>{ConvertInstance = ((o) =>{ return Convert.ToInt32(o); }) } },
{ new ConversionEntry<int, uint>{ConvertInstance = ((o) =>{ return Convert.ToInt32(o); }) } },
{ new ConversionEntry<int, ushort>{ConvertInstance = ((o) =>{ return Convert.ToInt32(o); }) } },
{ new ConversionEntry<int, byte>{ConvertInstance = ((o) =>{ return Convert.ToInt32(o); }) } },
// short conversion
{ new ConversionEntry<short, string>{ConvertInstance = ((o) =>{ return Convert.ToInt16(o); }) } },
{ new ConversionEntry<short, short>{ConvertInstance = ((o) =>{ return Convert.ToInt16(o); }) } },
{ new ConversionEntry<short, sbyte>{ConvertInstance = ((o) =>{ return Convert.ToInt16(o); }) } },
{ new ConversionEntry<short, ushort>{ConvertInstance = ((o) =>{ return Convert.ToInt16(o); }) } },
{ new ConversionEntry<short, byte>{ConvertInstance = ((o) =>{ return Convert.ToInt16(o); }) } },
// sbyte conversion
{ new ConversionEntry<sbyte, string>{ConvertInstance = ((o) =>{ return Convert.ToSByte(o); }) } },
{ new ConversionEntry<sbyte, sbyte>{ConvertInstance = ((o) =>{ return Convert.ToSByte(o); }) } },
{ new ConversionEntry<sbyte, byte>{ConvertInstance = ((o) =>{ return Convert.ToSByte(o); }) } },
// ulong conversion
{ new ConversionEntry<ulong, string>{ConvertInstance = ((o) =>{ return Convert.ToUInt64(o); }) } },
{ new ConversionEntry<ulong, long>{ConvertInstance = ((o) =>{ return Convert.ToUInt64(o); }) } },
{ new ConversionEntry<ulong, int>{ConvertInstance = ((o) =>{ return Convert.ToUInt64(o); }) } },
{ new ConversionEntry<ulong, short>{ConvertInstance = ((o) =>{ return Convert.ToUInt64(o); }) } },
{ new ConversionEntry<ulong, sbyte>{ConvertInstance = ((o) =>{ return Convert.ToUInt64(o); }) } },
{ new ConversionEntry<ulong, ulong>{ConvertInstance = ((o) =>{ return Convert.ToUInt64(o); }) } },
{ new ConversionEntry<ulong, uint>{ConvertInstance = ((o) =>{ return Convert.ToUInt64(o); }) } },
{ new ConversionEntry<ulong, ushort>{ConvertInstance = ((o) =>{ return Convert.ToUInt64(o); }) } },
{ new ConversionEntry<ulong, byte>{ConvertInstance = ((o) =>{ return Convert.ToUInt64(o); }) } },
// uint conversion
{ new ConversionEntry<uint, string>{ConvertInstance = ((o) =>{ return Convert.ToUInt32(o); }) } },
{ new ConversionEntry<uint, int>{ConvertInstance = ((o) =>{ return Convert.ToUInt32(o); }) } },
{ new ConversionEntry<uint, short>{ConvertInstance = ((o) =>{ return Convert.ToUInt32(o); }) } },
{ new ConversionEntry<uint, sbyte>{ConvertInstance = ((o) =>{ return Convert.ToUInt32(o); }) } },
{ new ConversionEntry<uint, uint>{ConvertInstance = ((o) =>{ return Convert.ToUInt32(o); }) } },
{ new ConversionEntry<uint, ushort>{ConvertInstance = ((o) =>{ return Convert.ToUInt32(o); }) } },
{ new ConversionEntry<uint, byte>{ConvertInstance = ((o) =>{ return Convert.ToUInt32(o); }) } },
// ushort conversion
{ new ConversionEntry<ushort, string>{ConvertInstance = ((o) =>{ return Convert.ToUInt16(o); }) } },
{ new ConversionEntry<ushort, short>{ConvertInstance = ((o) =>{ return Convert.ToUInt16(o); }) } },
{ new ConversionEntry<ushort, sbyte>{ConvertInstance = ((o) =>{ return Convert.ToUInt16(o); }) } },
{ new ConversionEntry<ushort, ushort>{ConvertInstance = ((o) =>{ return Convert.ToUInt16(o); }) } },
{ new ConversionEntry<ushort, byte>{ConvertInstance = ((o) =>{ return Convert.ToUInt16(o); }) } },
// byte conversion
{ new ConversionEntry<byte, string>{ConvertInstance = ((o) =>{ return Convert.ToByte(o); }) } },
{ new ConversionEntry<byte, sbyte>{ConvertInstance = ((o) =>{ return Convert.ToByte(o); }) } },
{ new ConversionEntry<byte, byte>{ConvertInstance = ((o) =>{ return Convert.ToByte(o); }) } },
// boolean conversion
{ new ConversionEntry<bool, string>{ConvertInstance = ((o) =>{ return Convert.ToBoolean(o); }) } },
{ new ConversionEntry<bool, bool>{ConvertInstance = ((o) =>{ return Convert.ToBoolean(o); }) } },
// char conversion
{ new ConversionEntry<char, char>{ConvertInstance = ((o) =>{ return Convert.ToChar(o); }) } },
};
public static Type ForIndex(NMS_TYPE_INDEX index)
{
int i = Convert.ToInt32(index);
if(i<0 || i >= (int)NMS_TYPE_INDEX.UNKOWN)
{
throw new IndexOutOfRangeException("Unrecognized NMS Type Index " + index);
}
else
{
return NMSTypes[i];
}
}
public static bool IsNMSType(object value)
{
bool result = false;
int index = 0;
Type t = NMSTypes[index];
while (t != null && !result)
{
result = t.Equals(value.GetType());
t = NMSTypes[++index];
}
return result;
}
public static bool CanConvertNMSType<T>(object value)
{
ConversionKey key = ConversionKey.GetKey(typeof(T), value.GetType());
return NMSTypeConversionSet.Contains(key);
}
public static T ConvertNMSType<T, S>(S value)
{
ConversionKey key = ConversionKey.GetKey(typeof(T), value.GetType());
ConversionEntry<T, S> converter = (ConversionEntry<T, S>)NMSTypeConversionTable[key];
if(converter == null)
{
throw new NMSTypeConversionException("Cannot convert between type : " + (typeof(T)).Name + ", and type: " + value.GetType().Name);
}
return converter.ConvertInstance(value);
}
public static T ConvertNMSType<T>(object value)
{
ConversionKey key = ConversionKey.GetKey(typeof(T), value.GetType());
NMSTypeConversionTable.TryGetValue(key, out ConversionEntry converter);
if (converter == null)
{
throw new NMSTypeConversionException("Cannot convert between type : " + (typeof(T)).Name + ", and type: " + value.GetType().Name);
}
return (T)converter.Convert(value);
}
public class NMSTypeConversionException : MessageFormatException
{
public NMSTypeConversionException() : base() { }
public NMSTypeConversionException(string message) : base(message) { }
}
#endregion
}
}