From 2116d744aecc0f1e6d86cc48b7da9d7eed640710 Mon Sep 17 00:00:00 2001 From: markpollack Date: Tue, 14 Oct 2008 03:02:58 +0000 Subject: [PATCH] SPRNET-936 - Add message converter to/from XML (NMS) --- .../Nms/Support/Converter/ITypeMapper.cs | 42 +++++ .../Nms/Support/Converter/TypeMapper.cs | 144 ++++++++++++++++++ .../Support/Converter/XmlMessageConverter.cs | 136 +++++++++++++++++ .../Spring.Messaging.Nms.2008.csproj | 3 + 4 files changed, 325 insertions(+) create mode 100644 src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/ITypeMapper.cs create mode 100644 src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/TypeMapper.cs create mode 100644 src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/XmlMessageConverter.cs diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/ITypeMapper.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/ITypeMapper.cs new file mode 100644 index 00000000..ac0361f3 --- /dev/null +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/ITypeMapper.cs @@ -0,0 +1,42 @@ + + +#region License + +/* + * Copyright 2002-2008 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 + +using System; + +namespace Spring.Messaging.Nms.Support.Converter +{ + /// + /// Provides a layer of indirection when adding the 'type' of the object as a message property. + /// + /// Mark Pollack + public interface ITypeMapper + { + string TypeIdFieldName + { + get; + } + + string FromType(Type typeOfObjectToConvert); + + Type ToType(string typeId); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/TypeMapper.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/TypeMapper.cs new file mode 100644 index 00000000..01ae76e1 --- /dev/null +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/TypeMapper.cs @@ -0,0 +1,144 @@ + + +using System; +using System.Collections; +using Spring.Core.TypeResolution; + +namespace Spring.Messaging.Nms.Support.Converter +{ + public class TypeMapper : ITypeMapper + { + private string defaultNamespace; + private string defaultAssemblyName; + + //Generics not used to support both 1.1 and 2.0 + private IDictionary idTypeMapping; + private IDictionary typeIdMapping; + + + //TODO generalize? + private string defaultHashtableTypeId = "Hashtable"; + + private Type defaultHashtableClass = typeof(Hashtable); + + public TypeMapper() + { + idTypeMapping = new Hashtable(); + typeIdMapping = new Hashtable(); + } + + + public IDictionary IdTypeMapping + { + get { return idTypeMapping; } + set { idTypeMapping = value; } + } + + public string TypeIdFieldName + { + get { return "__TypeId__"; } + } + + + public Type DefaultHashtableClass + { + set { defaultHashtableClass = value; } + } + + public string FromType(Type typeOfObjectToConvert) + { + + if (typeIdMapping.Contains(typeOfObjectToConvert)) + { + return typeIdMapping[typeOfObjectToConvert] as string; + } + else + { + if ( typeof (IDictionary).IsAssignableFrom(typeOfObjectToConvert)) + { + return defaultHashtableTypeId; + } + return typeOfObjectToConvert.Name; + } + } + + public Type ToType(string typeId) + { + if (idTypeMapping.Contains(typeId)) + { + return idTypeMapping[typeId] as Type; + } + else + { + if (typeId.Equals(defaultHashtableTypeId)) + { + return defaultHashtableClass; + } + string fullyQualifiedTypeName = defaultNamespace + "." + + typeId + ", " + + DefaultAssemblyName; + return TypeResolutionUtils.ResolveType(fullyQualifiedTypeName); + } + + } + + public string DefaultNamespace + { + get + { + return defaultNamespace; + } + set + { + defaultNamespace = value; + } + + } + + public string DefaultAssemblyName + { + get + { + return defaultAssemblyName; + } + set + { + defaultAssemblyName = value; + } + } + + public void AfterPropertiesSet() + { + ValidateIdTypeMapping(); + if (DefaultAssemblyName != null && DefaultNamespace == null) + { + throw new ArgumentException("Default Namespace required when DefaultAssemblyName is set."); + } + if (DefaultNamespace != null && DefaultAssemblyName == null) + { + throw new ArgumentException("Default Assembly Name required when DefaultNamespace is set."); + } + } + + + private void ValidateIdTypeMapping() + { + IDictionary finalIdTypeMapping = new Hashtable(); + foreach (DictionaryEntry entry in idTypeMapping) + { + string id = entry.Key.ToString(); + Type t = entry.Value as Type; + if (t == null) + { + //convert from string value. + string typeName = entry.Value.ToString(); + t = TypeResolutionUtils.ResolveType(typeName); + } + finalIdTypeMapping.Add(id,t); + typeIdMapping.Add(t,id); + + } + idTypeMapping = finalIdTypeMapping; + } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/XmlMessageConverter.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/XmlMessageConverter.cs new file mode 100644 index 00000000..2bb2d463 --- /dev/null +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Support/Converter/XmlMessageConverter.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections; +using System.IO; +using System.Text; +using System.Xml; +using System.Xml.Serialization; +using Apache.NMS; +using Spring.Messaging.Nms.Support.Converter; + +namespace Spring.Messaging.Nms.Support.Converter +{ + public class XmlMessageConverter : IMessageConverter + { + private IMessageConverter defaultMessageConverter = new SimpleMessageConverter(); + + + private ITypeMapper typeMapper; + + + public ITypeMapper TypeMapper + { + set { typeMapper = value; } + } + + public IMessage ToMessage(object objectToConvert, ISession session) + { + if (objectToConvert == null) + { + throw new MessageConversionException("Can't convert null object"); + } + try + { + if (objectToConvert.GetType().Equals(typeof (string)) || + typeof (IDictionary).IsAssignableFrom(objectToConvert.GetType()) || + objectToConvert.GetType().Equals(typeof (Byte[]))) + { + return defaultMessageConverter.ToMessage(objectToConvert, session); + } + else + { + string xmlString = GetXmlString(objectToConvert); + IMessage msg = session.CreateTextMessage(xmlString); + msg.Properties.SetString(typeMapper.TypeIdFieldName, typeMapper.FromType(objectToConvert.GetType())); + return msg; + } + } catch (Exception e) + { + throw new MessageConversionException("Can't convert object of type " + objectToConvert.GetType(), e); + } + } + + private string GetXmlString(object objectToConvert) + { + string xmlString; + XmlTextWriter xmlTextWriter = null; + MemoryStream memoryStream = null; + try + { + memoryStream = new MemoryStream(); + xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8); + XmlSerializer xs = new XmlSerializer(objectToConvert.GetType()); + xs.Serialize(xmlTextWriter, objectToConvert); + xmlString = UTF8ByteArrayToString(((MemoryStream) xmlTextWriter.BaseStream).ToArray()); + } catch (Exception e) + { + throw new MessageConversionException("Can't convert object of type " + objectToConvert.GetType(), e); + } finally + { + if (memoryStream != null) memoryStream.Close(); + if (xmlTextWriter != null) xmlTextWriter.Close(); + } + return xmlString; + } + + public object FromMessage(IMessage messageToConvert) + { + if (messageToConvert == null) + { + throw new MessageConversionException("Can't convert null message"); + } + try + { + string converterId = messageToConvert.Properties.GetString(typeMapper.TypeIdFieldName); + if (converterId == null) + { + return defaultMessageConverter.FromMessage(messageToConvert); + } + else + { + ITextMessage textMessage = messageToConvert as ITextMessage; + if (textMessage == null) + { + throw new MessageConversionException("Can't convert message of type " + + messageToConvert.GetType()); + } + + using (MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(textMessage.Text))) + { + + XmlSerializer xs = new XmlSerializer(GetTargetType(textMessage)); + XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8); + return xs.Deserialize(memoryStream); + } + } + } catch (Exception e) + { + throw new MessageConversionException("Can't convert message of type " + messageToConvert.GetType(), e); + } + } + + private Type GetTargetType(ITextMessage message) + { + return typeMapper.ToType(message.Properties.GetString(typeMapper.TypeIdFieldName)); + } + + + private String UTF8ByteArrayToString(Byte[] characters) + { + UTF8Encoding encoding = new UTF8Encoding(); + + String constructedString = encoding.GetString(characters); + + return (constructedString); + } + + + private Byte[] StringToUTF8ByteArray(String pXmlString) + { + UTF8Encoding encoding = new UTF8Encoding(); + + Byte[] byteArray = encoding.GetBytes(pXmlString); + + return byteArray; + } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Messaging.Nms/Spring.Messaging.Nms.2008.csproj b/src/Spring/Spring.Messaging.Nms/Spring.Messaging.Nms.2008.csproj index 4bc1e7f7..fcd0e2f3 100644 --- a/src/Spring/Spring.Messaging.Nms/Spring.Messaging.Nms.2008.csproj +++ b/src/Spring/Spring.Messaging.Nms/Spring.Messaging.Nms.2008.csproj @@ -84,8 +84,11 @@ + + +