blob: 2941103cdd00d834bd230d6edc3919248761838d [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.Linq;
using System.Text;
using System.Threading.Tasks;
using Apache.NMS;
using Amqp.Framing;
using Amqp.Types;
using Apache.NMS.AMQP.Message;
namespace Apache.NMS.AMQP.Util
{
/// <summary>
/// Utility class containing constant values for NMS message fields, and values.
/// Also contains Utility methods for NMS messagId/correlationId and Destinations.
/// </summary>
class MessageSupport
{
// "x-opt-jms-msg-type" values
public const byte JMS_TYPE_MSG = 0x00;
public const byte JMS_TYPE_OBJ = 0x01;
public const byte JMS_TYPE_MAP = 0x02;
public const byte JMS_TYPE_BYTE = 0x03;
public const byte JMS_TYPE_STRM = 0x04;
public const byte JMS_TYPE_TXT = 0x05;
// "x-opt-jms-dest" and "x-opt-jms-reply-to" values
public const byte JMS_DEST_TYPE_QUEUE = 0x00;
public const byte JMS_DEST_TYPE_TOPIC = 0x01;
public const byte JMS_DEST_TYPE_TEMP_QUEUE = 0x02;
public const byte JMS_DEST_TYPE_TEMP_TOPIC = 0x03;
// Message Serialization ENCODING Annotation keys
public const string JMS_AMQP_TYPE_ENCODING = "JMS_AMQP_TYPE_ENCODING";
public const string JMS_JAVA_ENCODING = "JMS_JAVA_ENCODING";
public const string JMS_DONET_ENCODING = "JMS_DOTNET_ENCODING";
// Message Content-type values
public const string OCTET_STREAM_CONTENT_TYPE = "application/octet-stream";
public const string SERIALIZED_JAVA_OBJECT_CONTENT_TYPE = "application/x-java-serialized-object";
// Amqp.Message priority default value
public static readonly byte DEFAULT_PRIORITY_BYTE = Convert.ToByte((int)NMSConstants.defaultPriority);
public static readonly Data EMPTY_DATA = new Data() { Binary = new byte[] { } };
public static readonly AmqpValue NULL_AMQP_VALUE_BODY = new AmqpValue() { Value = null };
// Amqp Message Outcome instances
public static readonly Amqp.Framing.Accepted ACCEPTED_INSTANCE = new Amqp.Framing.Accepted();
public static readonly Amqp.Framing.Released RELEASED_INSTANCE = new Amqp.Framing.Released();
public static readonly Amqp.Framing.Rejected REJECTED_INSTANCE = new Amqp.Framing.Rejected();
public static readonly Amqp.Framing.Modified MODIFIED_INSTANCE = new Amqp.Framing.Modified();
public static readonly Amqp.Framing.Modified MODIFIED_FAILED_INSTANCE = new Amqp.Framing.Modified() { DeliveryFailed = true };
public static readonly AckType DEFAULT_ACK_TYPE = AckType.ACCEPTED;
// Message Id constants
public const string NMS_ID_PREFIX = "ID:";
public const string AMQP_STRING_PREFIX = "AMQP_STRING:";
public const string AMQP_ULONG_PREFIX = "AMQP_ULONG:";
public const string AMQP_BINARY_PREFIX = "AMQP_BINARY:";
public const string AMQP_UUID_PREFIX = "AMQP_UUID:";
public const string AMQP_NO_PREFIX = "AMQP_NO_PREFIX:";
private const string AMQP_TYPE = "AMQP_";
private static readonly int NMS_ID_PREFIX_LENGTH = NMS_ID_PREFIX.Length;
private static readonly int AMQP_TYPE_LENGTH = AMQP_TYPE.Length;
private static readonly int AMQP_STRING_PREFIX_LENGTH = AMQP_STRING_PREFIX.Length;
private static readonly int AMQP_BINARY_PREFIX_LENGTH = AMQP_BINARY_PREFIX.Length;
private static readonly int AMQP_ULONG_PREFIX_LENGTH = AMQP_ULONG_PREFIX.Length;
private static readonly int AMQP_UUID_PREFIX_LENGTH = AMQP_UUID_PREFIX.Length;
private static readonly int AMQP_NO_PREFIX_LENGTH = AMQP_NO_PREFIX.Length;
private static readonly char[] HEX_CHARS = "0123456789ABCDEF".ToCharArray();
public static IDestination CreateDestinationFromMessage(Connection source, Properties properties, byte type, bool replyTo = false)
{
IDestination dest = null;
if(properties==null || source == null) { return dest; }
bool isPropertyNull = (!replyTo) ? properties.To != null : properties.ReplyTo != null;
if (isPropertyNull)
{
string destname = (!replyTo) ? properties.To : properties.ReplyTo;
destname = UriUtil.GetDestinationName(destname, source);
switch (type)
{
case JMS_DEST_TYPE_TEMP_QUEUE:
dest = new TemporaryQueue(source, destname);
break;
case JMS_DEST_TYPE_QUEUE:
dest = new Queue(source, destname);
break;
case JMS_DEST_TYPE_TEMP_TOPIC:
dest = new TemporaryTopic(source, destname);
break;
case JMS_DEST_TYPE_TOPIC:
dest = new Topic(source, destname);
break;
}
}
return dest;
}
public static sbyte GetValueForDestination(IDestination destination)
{
sbyte b = 0x00; // same as queue.
if (destination != null)
{
if (destination.IsTopic)
{
if (destination.IsTemporary)
{
return (sbyte)JMS_DEST_TYPE_TEMP_TOPIC;
}
else
{
return (sbyte)JMS_DEST_TYPE_TOPIC;
}
}
else if (destination.IsQueue)
{
if (destination.IsTemporary)
{
return (sbyte)JMS_DEST_TYPE_TEMP_QUEUE;
}
else
{
return (sbyte)JMS_DEST_TYPE_QUEUE;
}
}
}
return b;
}
public static byte GetValueForPriority(MsgPriority mp)
{
return Convert.ToByte((int)mp);
}
public static MsgPriority GetPriorityFromValue(byte value)
{
MsgPriority result = NMSConstants.defaultPriority;
switch (value)
{
case 0x00:
result = MsgPriority.Lowest;
break;
case 0x01:
result = MsgPriority.VeryLow;
break;
case 0x02:
result = MsgPriority.Low;
break;
case 0x03:
result = MsgPriority.AboveLow;
break;
case 0x04:
result = MsgPriority.BelowNormal;
break;
case 0x05:
result = MsgPriority.Normal;
break;
case 0x06:
result = MsgPriority.AboveNormal;
break;
case 0x07:
result = MsgPriority.High;
break;
case 0x08:
result = MsgPriority.VeryHigh;
break;
case 0x09:
result = MsgPriority.Highest;
break;
default:
break;
}
return result;
}
public static object CreateAMQPMessageId(string nmsId)
{
if(nmsId == null)
{
return null;
}
if (!HasNMSIdPrefix(nmsId))
{
// application specific msg id return as is.
return nmsId;
}
try
{
if (HasAMQPNoPrefix(nmsId, NMS_ID_PREFIX_LENGTH))
{
return nmsId.Substring(NMS_ID_PREFIX_LENGTH + AMQP_NO_PREFIX_LENGTH);
}
else if (HasAMQPStringPrefix(nmsId, NMS_ID_PREFIX_LENGTH))
{
return nmsId.Substring(NMS_ID_PREFIX_LENGTH + AMQP_STRING_PREFIX_LENGTH);
}
else if (HasAMQPBinaryPrefix(nmsId, NMS_ID_PREFIX_LENGTH))
{
string hexString = nmsId.Substring(NMS_ID_PREFIX_LENGTH + AMQP_BINARY_PREFIX_LENGTH).ToUpper();
return ToByteArray(hexString, nmsId);
}
else if (HasAMQPULongPrefix(nmsId, NMS_ID_PREFIX_LENGTH))
{
string ulongString = nmsId.Substring(NMS_ID_PREFIX_LENGTH + AMQP_ULONG_PREFIX_LENGTH);
return Convert.ToUInt64(ulongString);
}
else if (HasAMQPUuidPrefix(nmsId, NMS_ID_PREFIX_LENGTH))
{
string guidString = nmsId.Substring(NMS_ID_PREFIX_LENGTH + AMQP_UUID_PREFIX_LENGTH);
return Guid.Parse(guidString);
}
else
{
return nmsId;
}
}
catch (Exception e)
{
throw new NMSException("Id Conversion Failure. Provided Id: " + nmsId, e);
}
}
public static string CreateNMSMessageId(object amqpId)
{
if(null == amqpId)
{
return null;
}
if(amqpId is string)
{
string id = amqpId as string;
if (!HasNMSIdPrefix(id))
{
return NMS_ID_PREFIX + AMQP_NO_PREFIX + id;
}
else if (HasEncodingTypePrefix(id, NMS_ID_PREFIX_LENGTH))
{
return NMS_ID_PREFIX + AMQP_STRING_PREFIX + id;
}
else
{
return id;
}
}
else if (amqpId is Guid)
{
return NMS_ID_PREFIX + AMQP_UUID_PREFIX + amqpId.ToString();
}
else if (amqpId is ulong)
{
return NMS_ID_PREFIX + AMQP_ULONG_PREFIX + amqpId.ToString();
}
else if (amqpId is byte[])
{
return NMS_ID_PREFIX + AMQP_BINARY_PREFIX + ToHexString(amqpId as byte[]);
}
else
{
throw new NMSException("Unsupported Id Type provided: ", amqpId.GetType().FullName);
}
}
private static bool HasNMSIdPrefix(string id)
{
if(id == null)
{
return false;
}
return id.StartsWith(NMS_ID_PREFIX);
}
private static bool HasAMQPNoPrefix(string id, int offset)
{
if (id.Length - offset < AMQP_NO_PREFIX_LENGTH)
{
return false;
}
return id.IndexOf(AMQP_NO_PREFIX, offset, AMQP_NO_PREFIX_LENGTH) - offset == 0;
}
private static bool HasAMQPBinaryPrefix(string id, int offset)
{
if (id.Length - offset < AMQP_BINARY_PREFIX_LENGTH)
{
return false;
}
return id.IndexOf(AMQP_BINARY_PREFIX, offset, AMQP_BINARY_PREFIX_LENGTH) - offset == 0;
}
private static bool HasAMQPStringPrefix(string id, int offset)
{
if (id.Length - offset < AMQP_STRING_PREFIX_LENGTH)
{
return false;
}
return id.IndexOf(AMQP_STRING_PREFIX, offset, AMQP_STRING_PREFIX_LENGTH) - offset == 0;
}
private static bool HasAMQPULongPrefix(string id, int offset)
{
if (id.Length - offset < AMQP_ULONG_PREFIX_LENGTH)
{
return false;
}
return id.IndexOf(AMQP_ULONG_PREFIX, offset, AMQP_ULONG_PREFIX_LENGTH) - offset == 0;
}
private static bool HasAMQPUuidPrefix(string id, int offset)
{
if (id.Length - offset < AMQP_UUID_PREFIX_LENGTH)
{
return false;
}
return id.IndexOf(AMQP_UUID_PREFIX, offset, AMQP_UUID_PREFIX_LENGTH) - offset == 0;
}
private static bool HasEncodingTypePrefix(string id, int offset)
{
if (id.Length - offset < AMQP_NO_PREFIX_LENGTH)
{
return false;
}
if (id.IndexOf(AMQP_TYPE,offset, AMQP_TYPE_LENGTH) != 0)
{
return false;
}
return HasAMQPBinaryPrefix(id, offset) ||
HasAMQPNoPrefix(id, offset) ||
HasAMQPStringPrefix(id, offset) ||
HasAMQPULongPrefix(id, offset) ||
HasAMQPUuidPrefix(id, offset);
}
private static string ToHexString(byte[] bytes)
{
if(bytes == null)
{
return null;
}
StringBuilder sb = new StringBuilder(bytes.Length);
foreach(byte b in bytes)
{
int upper = (b >> 4) & 0x0F;
int lower = b & 0x0F;
sb.Append(HEX_CHARS[upper]);
sb.Append(HEX_CHARS[lower]);
}
return sb.ToString();
}
private static byte[] ToByteArray(string hex, string originalId)
{
if (hex == null || hex.Length % 2 != 0)
{
throw new NMSException("Invalid Binary MessageId " + originalId);
}
int size = hex.Length / 2;
int index = 0;
byte[] result = new byte[size];
for (int i=0; i<result.Length; i++)
{
char upper = hex[index];
index++;
char lower = hex[index];
index++;
char[] subchars = { upper, lower };
string substring = new string(subchars);
result[i] = Convert.ToByte(substring, 16);
}
return result;
}
}
}