using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Xml.Linq;
using System.Globalization;
using Technewlogic.ObjectLounge.Framework.BaseConcerns;
namespace Technewlogic.ObjectLounge.SyncProvider
{
public class XmlFieldSerializer
{
public XmlFieldSerializer()
{
_helper = new XmlFieldSerializerHelper();
}
private const string _entityTypeElementName = "BaseType";
private const string _relationshipElementName = "Relationships";
private const string _relationshipTargetTypeElementName = "TargetType";
private const string _propertyElementName = "Properties";
private readonly XmlFieldSerializerHelper _helper;
public XDocument SerializeEntity(
IUnitOfWorkConcern instance, Linker linker)
{
var currentCulture = CultureInfo.CurrentCulture;
try
{
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
Type proxyType = instance.GetType();
Type baseType = proxyType.BaseType;
XDocument root = new XDocument(
new XDeclaration("1.0", "utf-8", "true"));
// create the element for the type
var newElement = new XElement(baseType.Name);
newElement.Add(
new XElement(_entityTypeElementName, baseType.AssemblyQualifiedName));
root.Add(newElement);
// Serialize the entity relationships
var relationship = linker.GetRelationships(instance);
var relationshipElement = new XElement(_relationshipElementName);
newElement.Add(relationshipElement);
SerializeRelationships(relationshipElement, relationship);
// add the properties and sub-references
// IMP: Sub-References machen (Art "Value"-Types)
var propertiesElement = new XElement(_propertyElementName);
newElement.Add(propertiesElement);
SerializeProperties(instance, proxyType, propertiesElement);
return root;
}
finally
{
Thread.CurrentThread.CurrentCulture = currentCulture;
}
}
private void SerializeRelationships(
XElement element, EntityRelationship relationship)
{
foreach (var it in relationship.RelationshipHolder)
{
var targetTypeElement = new XElement(
_relationshipTargetTypeElementName,
it.TargetType.AssemblyQualifiedName);
element.Add(targetTypeElement);
foreach (var it2 in it.Targets)
{
var targetElement = new XElement(
"Target", it2);
targetTypeElement.Add(targetElement);
}
}
}
private void SerializeProperties(
object instance, Type type, XElement element)
{
foreach (var it in _helper.GetSerializationFields(type))
{
var value = it.GetValue(instance);
if (_helper.CheckIsSupportedType(it.FieldType) || value == null)
element.Add(new XElement(it.Name, value)); // leeres Feld, wenn null
// else ... TODO
}
}
public void DeserializeEntity(
string xmlData, IInstanceFactory instanceFactory, Linker linker)
{
var currentCulture = CultureInfo.CurrentCulture;
try
{
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
XDocument document = XDocument.Parse(xmlData);
var root = document.Elements().Single();
// get the type name
var baseTypeName = root
.Element(XName.Get(_entityTypeElementName))
.FirstNode.ToString();
var baseType = Type.GetType(baseTypeName);
if (baseType == null) // TODO: besser machen, und vor allem: identisch mit SupportedType
throw new ApplicationException(
"The given type '" + baseTypeName + "' " +
"could not be resolved.");
// create the instance
// HACK: An dieser Stelle sollte nichts mit Base Type auftauchen
var instance = instanceFactory.CreateInstance(baseType);
Type proxyType = instance.GetType();
// Deserialize the properties
var propertyElement = root.Element(XName.Get(_propertyElementName));
DeserializeProperties(instance, proxyType, propertyElement);
// Deserialize the relationships and register at the linker
var relationshipHolders = new List<RelationshipHolder>();
var relationshipElement = root.Element(XName.Get(_relationshipElementName));
foreach (var it in relationshipElement.Elements())
{
var targetTypeName = it.FirstNode.ToString();
var targetType = Type.GetType(targetTypeName);
if (targetType == null) // TODO: besser machen, und vor allem: identisch mit SupportedType
throw new ApplicationException(
"The given type '" + targetTypeName + "' " +
"could not be resolved.");
var targets = it
.Elements()
.Select(it2 => new Guid(it2.FirstNode.ToString()))
.ToArray();
var relationshipHolder = new RelationshipHolder(
targetType, targets);
relationshipHolders.Add(relationshipHolder);
}
linker.RegisterRelationships(new EntityRelationship(
instance, relationshipHolders));
}
finally
{
Thread.CurrentThread.CurrentCulture = currentCulture;
}
}
private void DeserializeProperties(object instance, Type type, XElement element)
{
// TODO: Wenn in der Konfiguration Elemente angegeben sind, die keine
// Entsprechung zu einem Property haben, werden diese ignoriert. Ist das gut?
foreach (var it in _helper.GetSerializationFields(type))
{
var fieldElement = element
.Element(XName.Get(it.Name));
if (fieldElement != null)
{
// Element leer? -> null
if (string.IsNullOrEmpty(element.Value))
it.SetValue(instance, null);
else if (_helper.CheckIsSupportedType(it.FieldType))
{
object value = _helper.CreateInstance(it.FieldType, fieldElement.Value);
it.SetValue(instance, value);
}
//else TODO
//{
// // IMP: StackOverflowException
// var deserializedObject = DeserializeObject(fieldElement);
// it.SetValue(instance, deserializedObject, null);
//}
}
//TODO: else exception???
}
}
}
}