Example #1
0
        /// <summary>
        /// Populates a list with items.
        /// </summary>
        /// <param name="state">The loader state.</param>
        /// <param name="list">The list to populate.</param>
        /// <param name="listElemType">The type of elements in the list.</param>
        /// <param name="element">The element that defines the list.</param>
        private void PopulateListItems(ObjectLoaderState state, Object list, Type listElemType, XElement element)
        {
            // Make sure that the list is properly defined.
            var itemsRoot = element.Element("Items");

            if (itemsRoot != null && itemsRoot.Elements().Where(x => x.Name != "Item").Any())
            {
                throw new InvalidOperationException(NucleusStrings.NonItemElementsInListDef);
            }

            // Populate the list's items.
            if (itemsRoot != null)
            {
                var add   = list.GetType().GetMethod("Add", new[] { listElemType });
                var items = itemsRoot.Elements("Item").ToList();

                for (int i = 0; i < items.Count; i++)
                {
                    var value = default(Object);
                    var type  = GetTypeFromElement(state, listElemType, items[i]);
                    if (items[i].Elements().Any())
                    {
                        value = CreateObject(state, type, null, GetSpecifiedConstructorArguments(items[i]));
                        value = PopulateObjectFromElements(state, value, items[i]);
                    }
                    else
                    {
                        value = ObjectResolver.FromString(items[i].Value, type);
                    }
                    add.Invoke(list, new[] { value });
                }
            }
        }
Example #2
0
 /// <summary>
 /// Populates an object with values.
 /// </summary>
 /// <param name="state">The loader state.</param>
 /// <param name="objectInstance">The object instance.</param>
 /// <param name="objectElement">The object element.</param>
 /// <returns>The object instance.</returns>
 private Object PopulateObject(ObjectLoaderState state, Object objectInstance, XElement objectElement)
 {
     objectInstance = PopulateObjectFromDefaults(state, objectInstance, objectElement);
     objectInstance = PopulateObjectFromAttributes(state, objectInstance, objectElement);
     objectInstance = PopulateObjectFromElements(state, objectInstance, objectElement);
     return(objectInstance);
 }
Example #3
0
        /// <summary>
        /// Populates an array value.
        /// </summary>
        /// <param name="state">The loader state.</param>
        /// <param name="member">The member to populate.</param>
        /// <param name="element">The element that defines the member's value.</param>
        private void PopulateArray(ObjectLoaderState state, ObjectLoaderMember member, XElement element)
        {
            // Make sure that the array is properly defined.
            var itemsRoot = element.Element("Items");

            if (itemsRoot != null && itemsRoot.Elements().Where(x => x.Name != "Item").Any())
            {
                throw new InvalidOperationException(NucleusStrings.NonItemElementsInArrayDef);
            }

            // Create the array.
            var items            = (itemsRoot == null) ? new List <XElement>() : itemsRoot.Elements("Item").ToList();
            var arrayElementType = member.MemberType.GetElementType();
            var array            = Array.CreateInstance(arrayElementType, items.Count);

            member.SetValueFromData(array, element);

            // Populate the array's items.
            for (int i = 0; i < items.Count; i++)
            {
                var value = default(Object);
                var type  = GetTypeFromElement(state, arrayElementType, items[i]);
                if (items[i].Elements().Any())
                {
                    value = CreateObject(state, type, null, GetSpecifiedConstructorArguments(items[i]));
                    value = PopulateObjectFromElements(state, value, items[i]);
                }
                else
                {
                    value = ObjectResolver.FromString(items[i].Value, type);
                }
                array.SetValue(value, i);
            }
        }
Example #4
0
        /// <summary>
        /// Populates an object from the currently loaded default values.
        /// </summary>
        /// <param name="state">The loader state.</param>
        /// <param name="objectInstance">The object instance.</param>
        /// <param name="objectElement">The object element.</param>
        /// <returns>The object instance.</returns>
        private Object PopulateObjectFromDefaults(ObjectLoaderState state, Object objectInstance, XElement objectElement)
        {
            // Find our inheritance chain.
            var typeStack   = new Stack <Type>();
            var typeCurrent = objectInstance.GetType();

            while (typeCurrent != null)
            {
                typeStack.Push(typeCurrent);
                typeCurrent = typeCurrent.BaseType;
            }

            // Populate the default values for the entire inheritance heirarchy.
            while (typeStack.Count > 0)
            {
                // Retrieve the defaults for the current type.
                var typeBeingPopulated = typeStack.Pop();
                var typeDefaults       = state.GetDefaultValues(typeBeingPopulated);
                if (typeDefaults == null)
                {
                    continue;
                }

                // Populate the default values.
                foreach (var typeDefault in typeDefaults)
                {
                    objectInstance = PopulateMemberFromElement(state, objectInstance, typeDefault.Value);
                }
            }

            return(objectInstance);
        }
Example #5
0
        /// <summary>
        /// Populates an enumerable value.
        /// </summary>
        /// <param name="state">The loader state.</param>
        /// <param name="member">The member to populate.</param>
        /// <param name="element">The element that defines the member's value.</param>
        private void PopulateEnumerable(ObjectLoaderState state, ObjectLoaderMember member, XElement element)
        {
            var listElemType = GetEnumerableElementType(element.Name.LocalName, member.MemberType);
            var listType     = typeof(List <>).MakeGenericType(listElemType);
            var listInstance = Activator.CreateInstance(listType);

            PopulateListItems(state, listInstance, listElemType, element);

            member.SetValueFromData(listInstance, element);
        }
Example #6
0
        /// <summary>
        /// Populates an object from the elements descending from the specified data element.
        /// </summary>
        /// <param name="state">The loader state.</param>
        /// <param name="objectInstance">The object instance.</param>
        /// <param name="objectElement">The object element.</param>
        /// <param name="filter">A filter which determines which elements are used to populate the object.</param>
        /// <returns>The object instance.</returns>
        private Object PopulateObjectFromElements(ObjectLoaderState state, Object objectInstance, XElement objectElement, Func <XElement, Boolean> filter = null)
        {
            var children = (filter == null) ? objectElement.Elements() : objectElement.Elements().Where(filter);

            foreach (var element in children)
            {
                objectInstance = PopulateMemberFromElement(state, objectInstance, element, false);
            }

            return(objectInstance);
        }
Example #7
0
        /// <summary>
        /// Creates an object from the specified root element.
        /// </summary>
        /// <param name="state">The loader state.</param>
        /// <param name="type">The type of object to create.</param>
        /// <param name="argsBase">The base set of arguments for this object's constructor.</param>
        /// <param name="argsSpecified">The specified set of arguments for this object's constructor.</param>
        /// <returns>The object that was created.</returns>
        private Object CreateObject(ObjectLoaderState state, Type type, Object[] argsBase, XElement[] argsSpecified = null)
        {
            var argsBaseLength      = (argsBase == null) ? 0 : argsBase.Length;
            var argsSpecifiedLength = (argsSpecified == null) ? 0 : argsSpecified.Length;

            // Try to find a constructor that matches our argument list.
            var ctorArgs = new Object[argsBaseLength + argsSpecifiedLength];
            var ctors    = type.GetConstructors();

            if (!ctors.Any() && argsBaseLength == 0 && argsSpecifiedLength == 0)
            {
                return(Activator.CreateInstance(type));
            }

            var ctorMatches = ctors.Where(x => x.GetParameters().Count() == ctorArgs.Length).ToList();

            if (!ctorMatches.Any())
            {
                throw new InvalidOperationException(NucleusStrings.CtorMatchNotFound);
            }
            if (ctorMatches.Count() > 1)
            {
                throw new InvalidOperationException(NucleusStrings.CtorMatchIsAmbiguous);
            }

            var ctorMatch  = ctorMatches.Single();
            var ctorParams = ctorMatch.GetParameters();

            // Build the complete list of constructor arguments.
            for (int i = 0; i < argsBaseLength; i++)
            {
                ctorArgs[i] = argsBase[i];
            }
            for (int i = 0; i < argsSpecifiedLength; i++)
            {
                var ctorArgElement = argsSpecified[i];
                var ctorArgType    = GetTypeFromElement(state, ctorParams[i + argsBase.Length].ParameterType, ctorArgElement);
                var ctorArgValue   = default(Object);
                if (ctorArgElement.Elements().Any())
                {
                    ctorArgValue = CreateObject(state, ctorArgType, null, GetSpecifiedConstructorArguments(ctorArgElement));
                    ctorArgValue = PopulateObjectFromElements(state, ctorArgValue, ctorArgElement);
                }
                else
                {
                    ctorArgValue = ParseValue(ctorArgElement.Value, ctorArgType, state.Culture);
                }
                ctorArgs[i + argsBase.Length] = ctorArgValue;
            }

            // Attempt to instantiate the object.
            return(ctorMatch.Invoke(ctorArgs));
        }
Example #8
0
        /// <summary>
        /// Loads an object from the specified XML element.
        /// </summary>
        /// <param name="resolver">A custom <see cref="ObjectLoaderMemberResolutionHandler"/> which allows external
        /// code to optionally resolve deserialized member values.</param>
        /// <param name="type">The type of object to load.</param>
        /// <param name="xml">The XML element that contains the object data.</param>
        /// <param name="culture">The culture information to use when parsing values.</param>
        /// <param name="ignoreMissingMembers">A value indicating whether the object loader
        /// should ignore members which do not exist on the type.</param>
        /// <returns>The object that was loaded.</returns>
        public Object LoadObject(ObjectLoaderMemberResolutionHandler resolver, Type type, XElement xml, CultureInfo culture, Boolean ignoreMissingMembers = false)
        {
            Contract.Require(type, nameof(type));
            Contract.Require(xml, nameof(xml));
            Contract.Require(culture, nameof(culture));

            var state = new ObjectLoaderState(globalAliases, culture, resolver);

            state.IgnoreMissingMembers = ignoreMissingMembers;
            state.ParseClassAliases(null, type);

            var objectElement  = xml;
            var objectInstance = CreateObjectFromRootElement(state, type, objectElement);

            return(PopulateObject(state, objectInstance, objectElement));
        }
Example #9
0
        /// <summary>
        /// Creates an object from the specified root element.
        /// </summary>
        /// <param name="state">The current loader state.</param>
        /// <param name="type">The type of object to create.</param>
        /// <param name="element">The element from which to create an object.</param>
        /// <returns>The object that was created.</returns>
        private Object CreateObjectFromRootElement(ObjectLoaderState state, Type type, XElement element)
        {
            // First, ensure that we have a class, key, and identifier.
            var objClassName = state.ResolveClass((String)element.Attribute("Class"));

            if (String.IsNullOrEmpty(objClassName))
            {
                throw new InvalidOperationException(NucleusStrings.DataObjectMissingClass);
            }

            // If we're loading a Nucleus data object, parse its unique key and ID.
            var argsBase = default(Object[]);

            if (typeof(DataObject).IsAssignableFrom(type))
            {
                var objKey = (String)element.Attribute("Key");
                if (String.IsNullOrEmpty(objKey))
                {
                    throw new InvalidOperationException(NucleusStrings.DataObjectMissingKey);
                }

                var objID = (String)element.Attribute("ID");
                if (String.IsNullOrEmpty(objID))
                {
                    throw new InvalidOperationException(NucleusStrings.DataObjectMissingID);
                }

                Guid objIDValue;
                if (!Guid.TryParse(objID, out objIDValue))
                {
                    throw new InvalidOperationException(NucleusStrings.DataObjectInvalidID.Format(objID));
                }

                argsBase = new Object[] { objKey, objIDValue };
            }

            // Attempt to find the object class and make sure it's of the correct type.
            var objClass = Type.GetType(objClassName, false);

            if (objClass == null || !type.IsAssignableFrom(objClass))
            {
                throw new InvalidOperationException(NucleusStrings.DataObjectInvalidClass.Format(objClassName ?? "(null)", argsBase[0]));
            }

            // Attempt to instantiate the object.
            return(CreateObject(state, objClass, argsBase, GetSpecifiedConstructorArguments(element)));
        }
Example #10
0
        /// <summary>
        /// Populates a list value.
        /// </summary>
        /// <param name="state">The loader state.</param>
        /// <param name="member">The member to populate.</param>
        /// <param name="element">The element that defines the member's value.</param>
        private void PopulateList(ObjectLoaderState state, ObjectLoaderMember member, XElement element)
        {
            // Create the list.
            var listImplType = GetListImplementationType(member.MemberType);
            var listElemType = GetListElementType(element.Name.LocalName, listImplType);
            var list         = Activator.CreateInstance(listImplType);

            // Populate the list's members.
            if (!member.IsIndexer)
            {
                PopulateObjectFromAttributes(state, list, element);
            }
            PopulateObjectFromElements(state, list, element, x => x.Name != "Items");
            PopulateListItems(state, list, listElemType, element);

            // Set the list on the object.
            member.SetValueFromData(list, element);
        }
Example #11
0
        /// <summary>
        /// Gets the type defined by the specified element.
        /// </summary>
        /// <param name="state">The loader state.</param>
        /// <param name="baseType">The base type.</param>
        /// <param name="element">The element to evaluate.</param>
        /// <returns>The type defined by the specified element.</returns>
        private Type GetTypeFromElement(ObjectLoaderState state, Type baseType, XElement element)
        {
            var complexTypeAttr = element.Attribute("Type");

            if (complexTypeAttr != null && String.IsNullOrEmpty(complexTypeAttr.Value))
            {
                throw new InvalidOperationException(NucleusStrings.DataObjectInvalidType.Format(element.Name));
            }

            var complexType = (complexTypeAttr == null) ? baseType : Type.GetType(state.ResolveClass(complexTypeAttr.Value), false);

            if (complexType == null)
            {
                throw new InvalidOperationException(NucleusStrings.DataObjectInvalidType.Format(element.Name));
            }

            if (!baseType.IsAssignableFrom(complexType))
            {
                throw new InvalidOperationException(NucleusStrings.DataObjectIncompatibleType.Format(element.Name));
            }

            return(complexType);
        }
Example #12
0
        /// <summary>
        /// Loads object definitions contained in the specified XML document.
        /// </summary>
        /// <typeparam name="T">The type of object to load.</typeparam>
        /// <param name="root">The root data element of the document that contains the object definitions to load.</param>
        /// <param name="aliases">The elements defining class aliases.</param>
        /// <param name="defaults">The elements defining class defaults.</param>
        /// <param name="name">The name of the type of object to load, which corresponds to the names of the elements in the XML file.</param>
        /// <param name="defaultClass">The name of the default class to apply to loaded objects.</param>
        public IEnumerable <T> LoadDefinitions <T>(XElement root,
                                                   IEnumerable <XElement> aliases, IEnumerable <XElement> defaults, String name, Type defaultClass) where T : DataObject
        {
            Contract.Require(root, nameof(root));
            Contract.Require(name, nameof(name));

            var cultureString = (String)root.Attribute("Culture");
            var culture       = String.IsNullOrWhiteSpace(cultureString) ? CultureInfo.InvariantCulture : new CultureInfo(cultureString);

            try
            {
                lockobj.EnterReadLock();

                var state = new ObjectLoaderState(globalAliases, culture);
                state.ParseClassAliases(aliases, defaultClass);
                state.ParseClassDefaults(defaults);

                var objectElements = root.Elements(name);
                var objectList     = new List <T>();

                foreach (var objectElement in objectElements)
                {
                    var objectInstance = (T)CreateObjectFromRootElement(state, typeof(T), objectElement);
                    PopulateObject(state, objectInstance, objectElement);
                    objectList.Add(objectInstance);
                }

                return(objectList);
            }
            finally
            {
                if (lockobj.IsReadLockHeld)
                {
                    lockobj.ExitReadLock();
                }
            }
        }
Example #13
0
        /// <summary>
        /// Populates an object from the attributes defined on the specified data element.
        /// </summary>
        /// <param name="state">The loader state.</param>
        /// <param name="objectInstance">The object instance.</param>
        /// <param name="objectElement">The object element.</param>
        /// <returns>The object instance.</returns>
        private Object PopulateObjectFromAttributes(ObjectLoaderState state, Object objectInstance, XElement objectElement)
        {
            foreach (var attr in objectElement.Attributes())
            {
                if (IsReservedKeyword(attr.Name.LocalName))
                {
                    continue;
                }

                var attrMember = ObjectLoaderMember.Find(objectInstance, attr.Name.LocalName, state.IgnoreMissingMembers);
                if (attrMember != null)
                {
                    if (state.Resolver != null && state.Resolver(objectInstance, attr.Name.LocalName, attr.Value))
                    {
                        continue;
                    }

                    var attrValue = ObjectResolver.FromString(attr.Value, attrMember.MemberType);
                    attrMember.SetValue(attrValue, null);
                }
            }

            return(objectInstance);
        }
Example #14
0
        /// <summary>
        /// Populates an object member from the specified data element.
        /// </summary>
        /// <param name="state">The loader state.</param>
        /// <param name="objectInstance">The object instance.</param>
        /// <param name="memberElement">The element that defines the member.</param>
        /// <param name="skipReservedKeywords">A value indicating whether to skip elements with the same names as reserved keywords.</param>
        /// <returns>The object instance.</returns>
        private Object PopulateMemberFromElement(ObjectLoaderState state, Object objectInstance, XElement memberElement, Boolean skipReservedKeywords = true)
        {
            if (IsReservedKeyword(memberElement.Name.LocalName))
            {
                if (skipReservedKeywords || IsForbiddenKeyword(memberElement.Name.LocalName))
                {
                    return(objectInstance);
                }
            }

            if (state.Resolver != null && state.Resolver(objectInstance, memberElement.Name.LocalName, memberElement.Value))
            {
                return(objectInstance);
            }

            var member = ObjectLoaderMember.Find(objectInstance, memberElement.Name.LocalName, state.IgnoreMissingMembers);

            if (member == null)
            {
                return(objectInstance);
            }

            // Handle array values.
            if (member.MemberType.IsArray)
            {
                PopulateArray(state, member, memberElement);
                return(objectInstance);
            }

            // Handle list values.
            if (IsListType(member.MemberType))
            {
                PopulateList(state, member, memberElement);
                return(objectInstance);
            }

            // Handle generic enumerables.
            if (IsEnumerableType(member.MemberType))
            {
                PopulateEnumerable(state, member, memberElement);
                return(objectInstance);
            }

            // Handle complex and simple objects.
            if (memberElement.Elements().Any())
            {
                var complexType      = GetTypeFromElement(state, member.MemberType, memberElement);
                var complexTypeValue = member.GetValueFromData(memberElement);
                if (complexTypeValue == null)
                {
                    complexTypeValue = CreateObject(state, complexType, null, GetSpecifiedConstructorArguments(memberElement));
                    if (!complexType.IsValueType)
                    {
                        member.SetValueFromData(complexTypeValue, memberElement);
                    }
                }

                if (!member.IsIndexer)
                {
                    complexTypeValue = PopulateObjectFromAttributes(state, complexTypeValue, memberElement);
                }
                complexTypeValue = PopulateObjectFromElements(state, complexTypeValue, memberElement);

                if (complexType.IsValueType)
                {
                    member.SetValueFromData(complexTypeValue, memberElement);
                }
            }
            else
            {
                if (String.IsNullOrEmpty(memberElement.Value))
                {
                    return(objectInstance);
                }

                var memberValue = ParseValue(memberElement.Value, member.MemberType, state.Culture);
                member.SetValueFromData(memberValue, memberElement);
            }

            return(objectInstance);
        }