Click here to Skip to main content
15,886,362 members
Articles / Programming Languages / C#

The Super Pool Framework

Rate me:
Please Sign up or sign in to vote.
4.87/5 (53 votes)
31 Aug 2010CPOL26 min read 100.8K   1.5K   178  
The Super Pool is a framework for decoupled communication and management of components. The Super Pool introduces a natural asynchronous communication environment into your solution that can be fluently spread over different components, threads, processes, or even computers or networks.
// -----
// Copyright 2010 Deyan Timnev
// This file is part of the Matrix Platform (www.matrixplatform.com).
// The Matrix Platform is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, 
// either version 3 of the License, or (at your option) any later version. The Matrix Platform is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
// without even the implied warranty of  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
// You should have received a copy of the GNU Lesser General Public License along with the Matrix Platform. If not, see http://www.gnu.org/licenses/lgpl.html
// -----
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Xml.Serialization;
using System.Xml;
using System.Reflection;
using Matrix.Common.Core;
using Matrix.Common.Core.Collections;
using Matrix.Common.Core.Results;

namespace Matrix.Common.Core.Serialization
{
    /// <summary>
    /// Helps in persisting objects. Provides surrogate selectors for serializing
    /// non serializables like Pen, Brush, etc.
    /// </summary>
    public static class SerializationHelper
    {
        /// <summary>
        /// Any serialization above this limit will produce a warning.
        /// </summary>
        public static int SerializationWarningLimit = 1024 * 1024;

        static IFormatter _formatter = null;
        static object _syncRoot = new object();

        const char MethodSerializationSeparator = '|';

        static BiDictionary<string, MethodBase> _methodSerializationCache = new BiDictionary<string, MethodBase>();


        /// <summary>
        /// Static constructor - create the default formatter.
        /// </summary>
        static SerializationHelper()
        {
            lock (_syncRoot)
            {
                if (_formatter != null)
                {
                    CoreSystemMonitor.Error("Not expected, formatter already created.");
                    return;
                }

                // Create the formatter.
                _formatter = new BinaryFormatter();

                // 2. Construct a SurrogateSelector object
                SurrogateSelector surrogateSelector = new SurrogateSelector();

                // 3. Tell the surrogate selector to use our object when a 
                // object is serialized/deserialized.
                List<ISerializationSurrogate> surrogates = ReflectionHelper.GetTypeChildrenInstances<ISerializationSurrogate>(
                    ReflectionHelper.GetAssemblies(true, true));

                foreach (ISerializationSurrogate surrogate in surrogates)
                {
                    SerializationSurrogateAttribute attribute = ReflectionHelper.GetTypeCustomAttributeInstance<SerializationSurrogateAttribute>(
                        surrogate.GetType(), false);

                    if (attribute != null)
                    {
                        surrogateSelector.AddSurrogate(attribute.Type, new StreamingContext(StreamingContextStates.All), surrogate);
                    }
                    else
                    {
                        CoreSystemMonitor.Info(string.Format("Surrogate type [{0}] not marked with SerializationSurrogateAttribute.", surrogate.GetType().Name));
                    }
                }

                _formatter.SurrogateSelector = surrogateSelector;
            }
        }

        public static IFormatter ObtainFormatter()
        {
            return _formatter;
        }

        /// <summary>
        /// Will clone the object using binary serialization.
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static object BinaryClone(object input)
        {
            byte[] bytes = Serialize(input);
            object result = null;
            if (Deserialize(bytes, out result).IsFailure)
            {
                return null;
            }

            return result;
        }

        /// <summary>
        /// Convert Method information to string representation.
        /// </summary>
        /// <param name="method"></param>
        /// <returns></returns>
        public static string SerializeMethodBaseToString(MethodBase method, bool useCache)
        {
            string result = null;
            if (useCache)
            {
                lock (_methodSerializationCache)
                {
                    if (_methodSerializationCache.TryGetByValue(method, ref result))
                    {
                        return result;
                    }
                }
            }

            StringBuilder valueBuilder = new StringBuilder();
            valueBuilder.Append(method.DeclaringType.AssemblyQualifiedName);
            valueBuilder.Append(MethodSerializationSeparator);
            valueBuilder.Append(method.Name);

            foreach (ParameterInfo parameter in method.GetParameters())
            {// Add parameters types.
                valueBuilder.Append(MethodSerializationSeparator);
                valueBuilder.Append(parameter.ParameterType.AssemblyQualifiedName);
            }

            result = valueBuilder.ToString();
            if (useCache)
            {
                lock (_methodSerializationCache)
                {// Possible multiple entry, but not a problem, also faster.
                    _methodSerializationCache.Add(result, method);
                }
            }

            return result;
        }

        /// <summary>
        /// Convert Method information from its string representation.
        /// </summary>
        /// <param name="methodInfo"></param>
        /// <returns></returns>
        public static MethodInfo DeserializeMethodBaseFromString(string methodInfoName, bool useCache)
        {
            if (useCache)
            {
                lock (_methodSerializationCache)
                {
                    MethodBase tmpResult = null;
                    if (_methodSerializationCache.TryGetByKey(methodInfoName, ref tmpResult))
                    {
                        return (MethodInfo)tmpResult;
                    }
                }
            }

            string[] values = methodInfoName.Split(MethodSerializationSeparator);
            if (values.Length < 2)
            {
                return null;
            }

            Type declaringType = Type.GetType(values[0]);
            string methodName = values[1];

            Type[] argumentsTypes = new Type[values.Length - 2];
            for (int i = 2; i < values.Length; i++)
            {
                argumentsTypes[i - 2] = Type.GetType(values[i]);
            }


            MethodInfo result = null;

            
            // *IMPORTANT*
            // We need to do this, in order to be able to obtain private methods too.

            MethodInfo[] methods= declaringType.GetMethods(BindingFlags.Default | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
            foreach (MethodInfo potentialMethodInfo in methods)
            {
                if (potentialMethodInfo.Name == methodName)
                {// Same name.
                    ParameterInfo[] parameters = potentialMethodInfo.GetParameters();
                    if (parameters.Length == argumentsTypes.Length)
                    {
                        bool parameterMatch = true;
                        for (int i = 0; i < parameters.Length; i++)
                        {
                            if (parameters[i].ParameterType != argumentsTypes[i])
                            {
                                parameterMatch = false;
                                break;
                            }
                        }

                        if (parameterMatch)
                        {
                            result = potentialMethodInfo;
                        }
                    }
                }

                if (result != null)
                {
                    break;
                }
            }

            if (useCache && result != null)
            {
                lock (_methodSerializationCache)
                {// Possible multiple entry, but not a problem, also faster.
                    _methodSerializationCache.Add(methodInfoName, result);
                }
            }
            
            return result;
        }

        /// <summary>
        /// Perform object serialization to a file.
        /// </summary>
        public static Result Serialize(string filename, object value)
        {
            try
            {
                // Create folder if not exists.
                if (Directory.Exists(Path.GetDirectoryName(filename)) == false)
                {
                    DirectoryInfo info = Directory.CreateDirectory(Path.GetDirectoryName(filename));
                    if (info == null || info.Exists == false)
                    {
                        return Result.Fail(string.Format("Failed to create directory [{0}].", Path.GetDirectoryName(filename)));
                    }
                }

                byte[] data = SerializationHelper.Serialize(value);
                File.WriteAllBytes(filename, data);
            }
            catch (Exception ex)
            {
                string message = string.Format("Failed to serialize to file [{0}]", filename);
                CoreSystemMonitor.OperationError(message, ex);
                return Result.Fail(message);
            }

            return Result.Success;
        }


        /// <summary>
        /// Perform object serialization to a array of bytes.
        /// </summary>
        public static byte[] Serialize(object p)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                Serialize(ms, p);
                ms.Flush();
                return ms.GetBuffer();
            }
        }

        /// <summary>
        /// Helper, overrides.
        /// </summary>
        public static Result Deserialize(byte[] data, out object value)
        {
            using (MemoryStream ms = new MemoryStream(data))
            {
                return Deserialize(ms, out value);
            }
        }

        /// <summary>
        /// Helper, overrides.
        /// </summary>
        public static TType Deserialize<TType>(string filename)
            where TType : class
        {
            try
            {
                byte[] data = File.ReadAllBytes(filename);
                if (data != null)
                {
                    object dummy;
                    SerializationHelper.Deserialize(data, out dummy);
                    return (TType)dummy;
                }
            }
            catch (Exception ex)
            {
                CoreSystemMonitor.OperationError("Failed to extract proxies manager.", ex);
            }

            return null;
        }

        /// <summary>
        /// Perform deserialization of an object from a stream.
        /// </summary>
        public static Result Deserialize(MemoryStream stream, out object value)
        {
            try
            {
                IFormatter formatter = ObtainFormatter();
                value = formatter.Deserialize(stream);
            }
            catch (Exception ex)
            {
                CoreSystemMonitor.Error("Failed to deserialize object.", ex);
                value = null;
                return Result.Fail(ex);
            }

            return Result.Success;
        }

        /// <summary>
        /// Serialize to memory stream.
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="p"></param>
        /// <returns></returns>
        public static Result Serialize(MemoryStream stream, object p)
        {
            try
            {
                IFormatter formatter = ObtainFormatter();
                formatter.Serialize(stream, p);
                if (stream.Position > SerializationWarningLimit)
                {
                    CoreSystemMonitor.Warning("Serialialization of object [" + p.GetType().Name + "] has grown above the default serialization limit to [" + stream.Position.ToString() + "] bytes.");
                }

                return Result.Success;
            }
            catch (Exception ex)
            {
                CoreSystemMonitor.Error("Failed to serialize object [" + p.GetType().Name + "," + ex.Message + "].");
                return Result.Fail(ex);
            }
        }

        /// <summary>
        /// Serialize to file.
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="p"></param>
        /// <returns></returns>
        public static Result SerializeXml(string filename, object p)
        {
            try
            {
                // Create folder if not exists.
                if (Directory.Exists(Path.GetDirectoryName(filename)) == false)
                {
                    DirectoryInfo info = Directory.CreateDirectory(Path.GetDirectoryName(filename));
                    if (info == null || info.Exists == false)
                    {
                        return Result.Fail(string.Format("Failed to create directory [{0}].", Path.GetDirectoryName(filename)));
                    }
                }

                using (XmlWriter xw = XmlWriter.Create(filename))
                {
                    return SerializationHelper.SerializeXml(xw, p);
                }
            }
            catch (Exception ex)
            {
                CoreSystemMonitor.OperationError("Failed to serialize object [" + p.ToString() + "] to xml file [" + filename + "].", ex);
                return Result.Failure;
            }
        }

        /// <summary>
        /// Serialize to string builder.
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="p"></param>
        /// <returns></returns>
        public static Result SerializeXml(StringBuilder builder, object p)
        {
            try
            {
                using (XmlWriter xw = XmlWriter.Create(builder))
                {
                    return SerializationHelper.SerializeXml(xw, p);
                }
            }
            catch (Exception ex)
            {
                CoreSystemMonitor.OperationError("Failed to serialize object [" + p.ToString() + "] to xml, string builder.", ex);
                return Result.Fail(ex);
            }
        }

        /// <summary>
        /// Serialize to memory stream.
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="p"></param>
        /// <returns></returns>
        public static Result SerializeXml(MemoryStream stream, object p)
        {
            try
            {
                using (XmlWriter xw = XmlWriter.Create(stream))
                {
                    return SerializationHelper.SerializeXml(xw, p);
                }
            }
            catch (Exception ex)
            {
                CoreSystemMonitor.OperationError("Failed to serialize object [" + p.ToString() + "] to xml stream.", ex);
                return Result.Fail(ex);
            }
        }

        /// <summary>
        /// Serialize to xml writer.
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="p"></param>
        /// <returns></returns>
        public static Result SerializeXml(XmlWriter writer, object p)
        {
            try
            {
                XmlSerializer serializer = new XmlSerializer(p.GetType());
                serializer.Serialize(writer, p, null);
            }
            catch (Exception ex)
            {
                CoreSystemMonitor.Error("Failed to xml-serialize object [" + p.GetType().Name + "]", ex);
                return Result.Fail(ex);
            }

            return Result.Success;
        }

        /// <summary>
        /// Serialize to text writer.
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="p"></param>
        /// <returns></returns>
        public static Result SerializeXml(TextWriter writer, object p)
        {
            try
            {
                XmlSerializer serializer = new XmlSerializer(p.GetType());
                serializer.Serialize(writer, p);
            }
            catch (Exception ex)
            {
                CoreSystemMonitor.Error("Failed to xml-serialize object [" + p.GetType().Name + "]", ex);
                return Result.Fail(ex);
            }

            return Result.Success;
        }

        public static Result DeSerializeXml<TType>(string file, out TType output)
            where TType : class
        {
            try
            {
                using (XmlReader reader = XmlTextReader.Create(file))
                {
                    return SerializationHelper.DeSerializeXml<TType>(reader, out output);
                }
            }
            catch (Exception ex)
            {
                output = null;
                return Result.Fail(ex);
            }
        }

        public static Result DeSerializeXml<TType>(XmlReader reader, out TType output)
            where TType : class
        {
            output = null;
            try
            {
                XmlSerializer serializer = new XmlSerializer(typeof(TType));
                output = (TType)serializer.Deserialize(reader);
            }
            catch (Exception ex)
            {
                CoreSystemMonitor.Error("Failed to xml-deserialize object [" + typeof(TType).Name + "]", ex);
                return Result.Fail(ex);
            }

            return Result.Success;
        }

        public static Result DeSerializeXml<TType>(MemoryStream reader, out TType output)
            where TType : class
        {
            output = null;
            try
            {
                XmlSerializer serializer = new XmlSerializer(typeof(TType));
                output = (TType)serializer.Deserialize(reader);
            }
            catch (Exception ex)
            {
                CoreSystemMonitor.Error("Failed to xml-deserialize object [" + typeof(TType).Name + "]", ex);
                return Result.Fail(ex);
            }

            return Result.Success;
        }

        public static Result DeSerializeXml<TType>(TextReader reader, out TType output)
            where TType : class
        {
            output = null;
            try
            {
                XmlSerializer serializer = new XmlSerializer(typeof(TType));
                output = (TType)serializer.Deserialize(reader);
            }
            catch (Exception ex)
            {
                CoreSystemMonitor.Error("Failed to xml-deserialize object [" + typeof(TType).Name + "]", ex);
                return Result.Fail(ex);
            }

            return Result.Success;
        }

        ///// <summary>
        ///// Special helper for doing data from a SerializationInfo.
        ///// </summary>
        //public static void SerializeInfo(Stream stream, SerializationInfo info)
        //{
        //    try
        //    {
        //        IFormatter formatter = GenerateFormatter();

        //        SerializationInfoEnumerator enumerator = info.GetEnumerator();
        //        while (enumerator.MoveNext())
        //        {
        //            formatter.SaveState(stream, enumerator.Current.Name);
        //            formatter.SaveState(stream, enumerator.Current.Value);
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        SystemMonitor.Error("Failed to serialize info [" + ex.Message + "].");
        //    }
        //}

        ///// <summary>
        ///// Special helper for doing data from a SerializationInfo.
        ///// </summary>
        //public static void DeSerializeInfo(SerializationInfo info, Stream stream)
        //{
        //    try
        //    {
        //        IFormatter formatter = GenerateFormatter();

        //        string name;
        //        do
        //        {
        //            name = (string)formatter.Deserialize(stream);
        //            object value = formatter.Deserialize(stream);
        //            info.AddValue(name, value);
        //        }
        //        while (string.IsNullOrEmpty(name) == false);
        //    }
        //    catch (Exception ex)
        //    {
        //        SystemMonitor.Error("Failed to serialize info [" + ex.Message + "].");
        //    }
        //}
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Product Manager Ingenious Ltd, Bulgaria
Bulgaria Bulgaria
I worked for a few years as a C++/Win32 developer and software architect, and then moved on to the .NET environment where I was able to discover the beauty of managed programming.

I am currently involved in the development and management of Open Forex Platform (www.openforexplatform.com) and the Matrix Platform (www.matrixplatform.com).

Comments and Discussions