From f17066b7bf27c22448d883e0af9d20a42f671b62 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 3 Feb 2012 22:21:54 +0000 Subject: Change LandDataSerializer deserialization so that in the future it won't care about extra elements or element order. This brings it into line with other deserializations such as object and will improve future backward compatibility. --- .../Serialization/External/LandDataSerializer.cs | 237 +++++++++++++++------ .../External/UserInventoryItemSerializer.cs | 3 +- .../External/UserProfileSerializer.cs | 5 +- .../Serialization/Tests/LandDataSerializerTests.cs | 37 +++- 4 files changed, 208 insertions(+), 74 deletions(-) (limited to 'OpenSim/Framework/Serialization') diff --git a/OpenSim/Framework/Serialization/External/LandDataSerializer.cs b/OpenSim/Framework/Serialization/External/LandDataSerializer.cs index 3ae9a8e..bf6c4e5 100644 --- a/OpenSim/Framework/Serialization/External/LandDataSerializer.cs +++ b/OpenSim/Framework/Serialization/External/LandDataSerializer.cs @@ -28,8 +28,10 @@ using System; using System.Collections.Generic; using System.IO; +using System.Reflection; using System.Text; using System.Xml; +using log4net; using OpenMetaverse; using OpenSim.Framework; @@ -40,8 +42,152 @@ namespace OpenSim.Framework.Serialization.External /// public class LandDataSerializer { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + protected static UTF8Encoding m_utf8Encoding = new UTF8Encoding(); + private delegate void LandDataProcessor(LandData landData, XmlTextReader reader); + private static Dictionary m_ldProcessors + = new Dictionary(); + + private delegate void LandAccessEntryProcessor(LandAccessEntry lae, XmlTextReader reader); + private static Dictionary m_laeProcessors + = new Dictionary(); + + static LandDataSerializer() + { + // LandData processors + m_ldProcessors.Add( + "Area", (ld, xtr) => ld.Area = Convert.ToInt32(xtr.ReadElementString("Area"))); + m_ldProcessors.Add( + "AuctionID", (ld, xtr) => ld.AuctionID = Convert.ToUInt32(xtr.ReadElementString("AuctionID"))); + m_ldProcessors.Add( + "AuthBuyerID", (ld, xtr) => ld.AuthBuyerID = UUID.Parse(xtr.ReadElementString("AuthBuyerID"))); + m_ldProcessors.Add( + "Category", (ld, xtr) => ld.Category = (ParcelCategory)Convert.ToSByte(xtr.ReadElementString("Category"))); + m_ldProcessors.Add( + "ClaimDate", (ld, xtr) => ld.ClaimDate = Convert.ToInt32(xtr.ReadElementString("ClaimDate"))); + m_ldProcessors.Add( + "ClaimPrice", (ld, xtr) => ld.ClaimPrice = Convert.ToInt32(xtr.ReadElementString("ClaimPrice"))); + m_ldProcessors.Add( + "GlobalID", (ld, xtr) => ld.GlobalID = UUID.Parse(xtr.ReadElementString("GlobalID"))); + m_ldProcessors.Add( + "GroupID", (ld, xtr) => ld.GroupID = UUID.Parse(xtr.ReadElementString("GroupID"))); + m_ldProcessors.Add( + "IsGroupOwned", (ld, xtr) => ld.IsGroupOwned = Convert.ToBoolean(xtr.ReadElementString("IsGroupOwned"))); + m_ldProcessors.Add( + "Bitmap", (ld, xtr) => ld.Bitmap = Convert.FromBase64String(xtr.ReadElementString("Bitmap"))); + m_ldProcessors.Add( + "Description", (ld, xtr) => ld.Description = xtr.ReadElementString("Description")); + m_ldProcessors.Add( + "Flags", (ld, xtr) => ld.Flags = Convert.ToUInt32(xtr.ReadElementString("Flags"))); + m_ldProcessors.Add( + "LandingType", (ld, xtr) => ld.LandingType = Convert.ToByte(xtr.ReadElementString("LandingType"))); + m_ldProcessors.Add( + "Name", (ld, xtr) => ld.Name = xtr.ReadElementString("Name")); + m_ldProcessors.Add( + "Status", (ld, xtr) => ld.Status = (ParcelStatus)Convert.ToSByte(xtr.ReadElementString("Status"))); + m_ldProcessors.Add( + "LocalID", (ld, xtr) => ld.LocalID = Convert.ToInt32(xtr.ReadElementString("LocalID"))); + m_ldProcessors.Add( + "MediaAutoScale", (ld, xtr) => ld.MediaAutoScale = Convert.ToByte(xtr.ReadElementString("MediaAutoScale"))); + m_ldProcessors.Add( + "MediaID", (ld, xtr) => ld.MediaID = UUID.Parse(xtr.ReadElementString("MediaID"))); + m_ldProcessors.Add( + "MediaURL", (ld, xtr) => ld.MediaURL = xtr.ReadElementString("MediaURL")); + m_ldProcessors.Add( + "MusicURL", (ld, xtr) => ld.MusicURL = xtr.ReadElementString("MusicURL")); + + m_ldProcessors.Add( + "ParcelAccessList", ProcessParcelAccessList); + + m_ldProcessors.Add( + "PassHours", (ld, xtr) => ld.PassHours = Convert.ToSingle(xtr.ReadElementString("PassHours"))); + m_ldProcessors.Add( + "PassPrice", (ld, xtr) => ld.PassPrice = Convert.ToInt32(xtr.ReadElementString("PassPrice"))); + m_ldProcessors.Add( + "SalePrice", (ld, xtr) => ld.SalePrice = Convert.ToInt32(xtr.ReadElementString("SalePrice"))); + m_ldProcessors.Add( + "SnapshotID", (ld, xtr) => ld.SnapshotID = UUID.Parse(xtr.ReadElementString("SnapshotID"))); + m_ldProcessors.Add( + "UserLocation", (ld, xtr) => ld.UserLocation = Vector3.Parse(xtr.ReadElementString("UserLocation"))); + m_ldProcessors.Add( + "UserLookAt", (ld, xtr) => ld.UserLookAt = Vector3.Parse(xtr.ReadElementString("UserLookAt"))); + + // No longer used here // + // m_ldProcessors.Add("Dwell", (landData, xtr) => return); + + m_ldProcessors.Add( + "OtherCleanTime", (ld, xtr) => ld.OtherCleanTime = Convert.ToInt32(xtr.ReadElementString("OtherCleanTime"))); + + // LandAccessEntryProcessors + m_laeProcessors.Add( + "AgentID", (lae, xtr) => lae.AgentID = UUID.Parse(xtr.ReadElementString("AgentID"))); + m_laeProcessors.Add( + "Time", (lae, xtr) => + { + // We really don't care about temp vs perm here and this + // would break on old oars. Assume all bans are perm + xtr.ReadElementString("Time"); + lae.Expires = 0; // Convert.ToUint( xtr.ReadElementString("Time")); + } + ); + m_laeProcessors.Add( + "AccessList", (lae, xtr) => lae.Flags = (AccessList)Convert.ToUInt32(xtr.ReadElementString("AccessList"))); + } + + public static void ProcessParcelAccessList(LandData ld, XmlTextReader xtr) + { + if (!xtr.IsEmptyElement) + { + while (xtr.Read() && xtr.NodeType != XmlNodeType.EndElement) + { + LandAccessEntry lae = new LandAccessEntry(); + + xtr.ReadStartElement("ParcelAccessEntry"); + + string nodeName = string.Empty; + while (xtr.NodeType != XmlNodeType.EndElement) + { + nodeName = xtr.Name; + +// m_log.DebugFormat("[LandDataSerializer]: Processing: {0} in ParcelAccessEntry", nodeName); + + LandAccessEntryProcessor p = null; + if (m_laeProcessors.TryGetValue(xtr.Name, out p)) + { +// m_log.DebugFormat("[LandDataSerializer]: Found {0} processor in ParcelAccessEntry", nodeName); + + try + { + p(lae, xtr); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[LandDataSerializer]: Exception while parsing element {0} in ParcelAccessEntry, continuing. Exception {1}{2}", + nodeName, e.Message, e.StackTrace); + + if (xtr.NodeType == XmlNodeType.EndElement) + xtr.Read(); + } + } + else + { + // m_log.DebugFormat("[LandDataSerializer]: caught unknown element {0}", nodeName); + xtr.ReadOuterXml(); // ignore + } + } + + xtr.ReadEndElement(); + + ld.ParcelAccessList.Add(lae); + } + } + + xtr.Read(); + } + /// /// Reify/deserialize landData /// @@ -63,72 +209,43 @@ namespace OpenSim.Framework.Serialization.External { LandData landData = new LandData(); - StringReader sr = new StringReader(serializedLandData); - XmlTextReader xtr = new XmlTextReader(sr); - - xtr.ReadStartElement("LandData"); - - landData.Area = Convert.ToInt32( xtr.ReadElementString("Area")); - landData.AuctionID = Convert.ToUInt32( xtr.ReadElementString("AuctionID")); - landData.AuthBuyerID = UUID.Parse( xtr.ReadElementString("AuthBuyerID")); - landData.Category = (ParcelCategory)Convert.ToSByte( xtr.ReadElementString("Category")); - landData.ClaimDate = Convert.ToInt32( xtr.ReadElementString("ClaimDate")); - landData.ClaimPrice = Convert.ToInt32( xtr.ReadElementString("ClaimPrice")); - landData.GlobalID = UUID.Parse( xtr.ReadElementString("GlobalID")); - landData.GroupID = UUID.Parse( xtr.ReadElementString("GroupID")); - landData.IsGroupOwned = Convert.ToBoolean( xtr.ReadElementString("IsGroupOwned")); - landData.Bitmap = Convert.FromBase64String( xtr.ReadElementString("Bitmap")); - landData.Description = xtr.ReadElementString("Description"); - landData.Flags = Convert.ToUInt32( xtr.ReadElementString("Flags")); - landData.LandingType = Convert.ToByte( xtr.ReadElementString("LandingType")); - landData.Name = xtr.ReadElementString("Name"); - landData.Status = (ParcelStatus)Convert.ToSByte( xtr.ReadElementString("Status")); - landData.LocalID = Convert.ToInt32( xtr.ReadElementString("LocalID")); - landData.MediaAutoScale = Convert.ToByte( xtr.ReadElementString("MediaAutoScale")); - landData.MediaID = UUID.Parse( xtr.ReadElementString("MediaID")); - landData.MediaURL = xtr.ReadElementString("MediaURL"); - landData.MusicURL = xtr.ReadElementString("MusicURL"); - landData.OwnerID = UUID.Parse( xtr.ReadElementString("OwnerID")); - - landData.ParcelAccessList = new List(); - xtr.Read(); - if (xtr.Name != "ParcelAccessList") - throw new XmlException(String.Format("Expected \"ParcelAccessList\" element but got \"{0}\"", xtr.Name)); - - if (!xtr.IsEmptyElement) + using (XmlTextReader reader = new XmlTextReader(new StringReader(serializedLandData))) { - while (xtr.Read() && xtr.NodeType != XmlNodeType.EndElement) - { - LandAccessEntry pae = new LandAccessEntry(); + reader.ReadStartElement("LandData"); - xtr.ReadStartElement("ParcelAccessEntry"); - pae.AgentID = UUID.Parse( xtr.ReadElementString("AgentID")); - // We really don't care about temp vs perm here and this - // would break on old oars. Assume all bans are perm - xtr.ReadElementString("Time"); - pae.Expires = 0; // Convert.ToUint( xtr.ReadElementString("Time")); - pae.Flags = (AccessList)Convert.ToUInt32( xtr.ReadElementString("AccessList")); - xtr.ReadEndElement(); + string nodeName = string.Empty; + while (reader.NodeType != XmlNodeType.EndElement) + { + nodeName = reader.Name; - landData.ParcelAccessList.Add(pae); - } - } - xtr.Read(); +// m_log.DebugFormat("[LandDataSerializer]: Processing: {0}", nodeName); - landData.PassHours = Convert.ToSingle( xtr.ReadElementString("PassHours")); - landData.PassPrice = Convert.ToInt32( xtr.ReadElementString("PassPrice")); - landData.SalePrice = Convert.ToInt32( xtr.ReadElementString("SalePrice")); - landData.SnapshotID = UUID.Parse( xtr.ReadElementString("SnapshotID")); - landData.UserLocation = Vector3.Parse( xtr.ReadElementString("UserLocation")); - landData.UserLookAt = Vector3.Parse( xtr.ReadElementString("UserLookAt")); - // No longer used here - xtr.ReadElementString("Dwell"); - landData.OtherCleanTime = Convert.ToInt32( xtr.ReadElementString("OtherCleanTime")); + LandDataProcessor p = null; + if (m_ldProcessors.TryGetValue(reader.Name, out p)) + { + try + { + p(landData, reader); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[LandDataSerializer]: exception while parsing element {0}, continuing. Exception {1}{2}", + nodeName, e.Message, e.StackTrace); - xtr.ReadEndElement(); + if (reader.NodeType == XmlNodeType.EndElement) + reader.Read(); + } + } + else + { + // m_log.DebugFormat("[LandDataSerializer]: caught unknown element {0}", nodeName); + reader.ReadOuterXml(); // ignore + } + } - xtr.Close(); - sr.Close(); + reader.ReadEndElement(); + } return landData; } diff --git a/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs b/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs index f138437..5d986d5 100644 --- a/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs +++ b/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs @@ -41,8 +41,7 @@ namespace OpenSim.Framework.Serialization.External { /// /// Serialize and deserialize user inventory items as an external format. - /// - /// XXX: Please do not use yet. + /// public class UserInventoryItemSerializer { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); diff --git a/OpenSim/Framework/Serialization/External/UserProfileSerializer.cs b/OpenSim/Framework/Serialization/External/UserProfileSerializer.cs index f50b49a..c685a15 100644 --- a/OpenSim/Framework/Serialization/External/UserProfileSerializer.cs +++ b/OpenSim/Framework/Serialization/External/UserProfileSerializer.cs @@ -33,8 +33,11 @@ using OpenSim.Framework; namespace OpenSim.Framework.Serialization.External { /// - /// Serialize and deserialize region settings as an external format. + /// Serialize and deserialize user profiles as an external format. /// + /// + /// Currently UNUSED. + /// public class UserProfileSerializer { public const int MAJOR_VERSION = 0; diff --git a/OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs b/OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs index 3607ce8..11a3a0a 100644 --- a/OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs +++ b/OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs @@ -27,11 +27,12 @@ using System; using System.Collections.Generic; -using OpenSim.Framework; -using OpenSim.Framework.Serialization.External; using OpenMetaverse; using OpenMetaverse.StructuredData; using NUnit.Framework; +using OpenSim.Framework; +using OpenSim.Framework.Serialization.External; +using OpenSim.Tests.Common; namespace OpenSim.Framework.Serialization.Tests { @@ -92,6 +93,8 @@ namespace OpenSim.Framework.Serialization.Tests [Test] public void LandDataSerializerSerializeTest() { + TestHelpers.InMethod(); + string serialized = LandDataSerializer.Serialize(this.land).Replace("\r\n", "\n"); Assert.That(serialized.Length > 0, "Serialize(LandData) returned empty string"); @@ -112,20 +115,32 @@ namespace OpenSim.Framework.Serialization.Tests /// Test the LandDataSerializer.Deserialize() method /// [Test] - public void TestLandDataSerializerDeserializeFromStringTest() + public void TestLandDataDeserializeNoAccessLists() + { + TestHelpers.InMethod(); + log4net.Config.XmlConfigurator.Configure(); + + LandData ld = LandDataSerializer.Deserialize(LandDataSerializerTest.preSerialized); + Assert.That(ld != null, "Deserialize(string) returned null"); + Assert.That(ld.GlobalID == this.land.GlobalID, "Reified LandData.GlobalID != original LandData.GlobalID"); + Assert.That(ld.Name == this.land.Name, "Reified LandData.Name != original LandData.Name"); + } + + [Test] + public void TestLandDataDeserializeWithAccessLists() { - LandData reifiedLandData = LandDataSerializer.Deserialize(LandDataSerializerTest.preSerialized); - Assert.That(reifiedLandData != null, "Deserialize(string) returned null"); - Assert.That(reifiedLandData.GlobalID == this.land.GlobalID, "Reified LandData.GlobalID != original LandData.GlobalID"); - Assert.That(reifiedLandData.Name == this.land.Name, "Reified LandData.Name != original LandData.Name"); + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); - LandData reifiedLandDataWithParcelAccessList = LandDataSerializer.Deserialize(LandDataSerializerTest.preSerializedWithParcelAccessList); - Assert.That(reifiedLandDataWithParcelAccessList != null, + LandData ld = LandDataSerializer.Deserialize(LandDataSerializerTest.preSerializedWithParcelAccessList); + Assert.That(ld != null, "Deserialize(string) returned null (pre-serialized with parcel access list)"); - Assert.That(reifiedLandDataWithParcelAccessList.GlobalID == this.landWithParcelAccessList.GlobalID, + Assert.That(ld.GlobalID == this.landWithParcelAccessList.GlobalID, "Reified LandData.GlobalID != original LandData.GlobalID (pre-serialized with parcel access list)"); - Assert.That(reifiedLandDataWithParcelAccessList.Name == this.landWithParcelAccessList.Name, + Assert.That(ld.Name == this.landWithParcelAccessList.Name, "Reified LandData.Name != original LandData.Name (pre-serialized with parcel access list)"); + Assert.That(ld.ParcelAccessList.Count, Is.EqualTo(2)); + Assert.That(ld.ParcelAccessList[0].AgentID, Is.EqualTo(UUID.Parse("62d65d45-c91a-4f77-862c-46557d978b6c"))); } } } -- cgit v1.1