Skip to content
Permalink
Browse files
Added support for serializing/deserializing objects via XML format fo…
…r easy cross-platform communication.

Fixes [AMQNET-156]. (See https://issues.apache.org/activemq/browse/AMQNET-156)
  • Loading branch information
Jim Gomes committed Apr 7, 2009
1 parent 6020d31 commit de35197a505346a0db6135b18dc14a8672a7944b
Show file tree
Hide file tree
Showing 6 changed files with 280 additions and 2 deletions.
@@ -14,12 +14,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System;
using System.Reflection;

namespace Apache.NMS.Util
{
public class NMSConvert
{
/// <summary>
/// Convert the acknowledgment mode string into AcknowledgementMode enum.
/// </summary>
/// <param name="ackText"></param>
/// <returns>Equivalent enum value. If unknown string is encounted, it will default to AutoAcknowledge.</returns>
public static AcknowledgementMode ToAcknowledgementMode(string ackText)
{
if(String.Compare(ackText, "AutoAcknowledge", true) == 0)
@@ -43,5 +49,73 @@ public static AcknowledgementMode ToAcknowledgementMode(string ackText)
return AcknowledgementMode.AutoAcknowledge;
}
}

/// <summary>
/// Convert an object into a text message. The object must be serializable to XML.
/// </summary>
public static ITextMessage ToXmlMessage(IMessageProducer producer, object obj)
{
ITextMessage message = producer.CreateTextMessage(XmlUtil.Serialize(obj));

// Embed the type into the message
message.NMSType = obj.GetType().FullName;
return message;
}

/// <summary>
/// Convert an object into a text message. The object must be serializable to XML.
/// </summary>
public static ITextMessage ToXmlMessage(ISession session, object obj)
{
ITextMessage message = session.CreateTextMessage(XmlUtil.Serialize(obj));

// Embed the type into the message
message.NMSType = obj.GetType().FullName;
return message;
}

/// <summary>
/// Convert a text message into an object. The object must be serializable from XML.
/// </summary>
public static object FromXmlMessage(IMessage message)
{
ITextMessage textMessage = message as ITextMessage;

if(null == textMessage)
{
return null;
}

Type objType = GetRuntimeType(textMessage.NMSType);
if(null == objType)
{
Tracer.ErrorFormat("Could not load type for {0} while deserializing XML object.", textMessage.NMSType);
return null;
}

return XmlUtil.Deserialize(objType, textMessage.Text);
}

/// <summary>
/// Get the runtime type for the class name. This routine will search all loaded
/// assemblies in the current App Domain to find the type.
/// </summary>
/// <param name="typeName">Full name of the type.</param>
/// <returns>Type object if found, or null if not found.</returns>
private static Type GetRuntimeType(string typeName)
{
Type objType = null;

foreach(Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
objType = assembly.GetType(typeName, false, true);
if(null != objType)
{
break;
}
}

return objType;
}
}
}
@@ -0,0 +1,76 @@
/*
* 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.IO;
using System.Text;
using System.Xml.Serialization;

namespace Apache.NMS.Util
{
/// <summary>
/// Class to provide support for working with Xml objects.
/// </summary>
public class XmlUtil
{
public static string Serialize(object obj)
{
XmlSerializer serializer = new XmlSerializer(obj.GetType());
StringWriter writer = new StringWriter(new StringBuilder(4096));

/*
* If the XML document has been altered with unknown
* nodes or attributes, handle them with the
* UnknownNode and UnknownAttribute events.
*/
serializer.UnknownNode += new XmlNodeEventHandler(serializer_UnknownNode);
serializer.UnknownAttribute += new XmlAttributeEventHandler(serializer_UnknownAttribute);
serializer.Serialize(writer, obj);
return writer.ToString();
}

public static object Deserialize(Type objType, string text)
{
if(null == text)
{
return null;
}

XmlSerializer serializer = new XmlSerializer(objType);
/*
* If the XML document has been altered with unknown
* nodes or attributes, handle them with the
* UnknownNode and UnknownAttribute events.
*/
serializer.UnknownNode += new XmlNodeEventHandler(serializer_UnknownNode);
serializer.UnknownAttribute += new XmlAttributeEventHandler(serializer_UnknownAttribute);
return serializer.Deserialize(new StringReader(text));
}

private static void serializer_UnknownNode(object sender, XmlNodeEventArgs e)
{
Tracer.ErrorFormat("Unknown Node: {0}\t{1}", e.Name, e.Text);
}

private static void serializer_UnknownAttribute(object sender, XmlAttributeEventArgs e)
{
Tracer.ErrorFormat("Unknown attribute: {0}='{1}'", e.Attr.Name, e.Attr.Value);
}

}
}

@@ -58,7 +58,6 @@ public void FilterIgnoredMessagesTest(bool persistent, string destinationName)
{
IDestination destination1 = CreateDestination(session1, destinationName);
IDestination destination2 = SessionUtil.GetDestination(session2, destinationName);
IDestination destination3 = SessionUtil.GetDestination(session2, destinationName);

using(IMessageProducer producer = session1.CreateProducer(destination1))
using(IMessageConsumer consumer1 = session2.CreateConsumer(destination2, "JMSType NOT LIKE '%IGNORE'"))
@@ -0,0 +1,127 @@
/*
* 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.Xml.Schema;
using System.Xml.Serialization;
using Apache.NMS.Util;
using NUnit.Framework;

namespace Apache.NMS.Test
{
// Serializable object. In real life, this type of object would be generated from
// an XSD file using XSDObjectGen.
[Serializable]
public enum CheckType
{
// [XmlEnum(Name = "message")]
message,
// [XmlEnum(Name = "command")]
command,
// [XmlEnum(Name = "response")]
response
}

[XmlRoot(ElementName = "NMSTestXmlType1", IsNullable = false), Serializable]
public class NMSTestXmlType1
{
// [XmlElement(ElementName = "crcCheck", IsNullable = false, DataType = "int")]
public int crcCheck;

// [XmlElement(Type = typeof(CheckType), ElementName = "checkType", IsNullable = false)]
public CheckType checkType;

public NMSTestXmlType1()
{
crcCheck = 0;
checkType = CheckType.message;
}
}

[XmlRoot(ElementName = "NMSTestXmlType2", IsNullable = false), Serializable]
public class NMSTestXmlType2
{
// [XmlElement(ElementName = "stringCheck", IsNullable = false, DataType = "string")]
public string stringCheck;

public NMSTestXmlType2()
{
stringCheck = String.Empty;
}
}

[TestFixture]
public class XmlMessageTest : NMSTestSupport
{
protected static string DESTINATION_NAME = "XmlMessageDestination";
protected static string TEST_CLIENT_ID = "XmlMessageClientId";

[Test]
public void SendReceiveXmlMessage()
{
using(IConnection connection = CreateConnection(TEST_CLIENT_ID))
{
connection.Start();
using(ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge))
{
IDestination destination = SessionUtil.GetDestination(session, DESTINATION_NAME);
using(IMessageConsumer consumer = session.CreateConsumer(destination))
using(IMessageProducer producer = session.CreateProducer(destination))
{
producer.RequestTimeout = receiveTimeout;

NMSTestXmlType1 srcIntObject = new NMSTestXmlType1();
srcIntObject.crcCheck = 0xbadf00d;
srcIntObject.checkType = CheckType.command;
producer.Send(NMSConvert.ToXmlMessage(session, srcIntObject));

NMSTestXmlType2 srcStringObject = new NMSTestXmlType2();
srcStringObject.stringCheck = "BadFood";
producer.Send(NMSConvert.ToXmlMessage(session, srcStringObject));

// Demonstrate the ability to generically handle multiple object types
// sent to the same consumer. If only one object type is ever sent to
// the destination, then a simple inline cast is all that is necessary
// when calling the NMSConvert.FromXmlMessage() function.

for(int index = 0; index < 2; index++)
{
object receivedObject = NMSConvert.FromXmlMessage(consumer.Receive(receiveTimeout));
Assert.IsNotNull(receivedObject, "Failed to retrieve XML message object.");

if(receivedObject is NMSTestXmlType1)
{
NMSTestXmlType1 destObject = (NMSTestXmlType1) receivedObject;
Assert.AreEqual(srcIntObject.crcCheck, destObject.crcCheck, "CRC integer mis-match.");
Assert.AreEqual(srcIntObject.checkType, destObject.checkType, "Check type mis-match.");
}
else if(receivedObject is NMSTestXmlType2)
{
NMSTestXmlType2 destObject = (NMSTestXmlType2) receivedObject;
Assert.AreEqual(srcStringObject.stringCheck, destObject.stringCheck, "CRC string mis-match.");
}
else
{
Assert.Fail("Invalid object type.");
}
}
}
}
}
}
}
}
@@ -103,6 +103,7 @@
<Compile Include="src\test\csharp\TransactionTest.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="src\test\csharp\XmlMessage.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="vs2008-nms.csproj">
@@ -93,6 +93,7 @@
<Compile Include="src\main\csharp\Util\URISupport.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="src\main\csharp\Util\XmlUtils.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="LICENSE.txt">

0 comments on commit de35197

Please sign in to comment.