csharp/apache/activemq-nms-api/src/nms-api/Util/PrimitiveMap.cs

PrimitiveMap.cs
/*
 * 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.Collections;
using System.IO;

namespace Apache.NMS.Util
{
    /// 
    /// A default implementation of IPrimitiveMap
    /// 
    public clast PrimitiveMap : IPrimitiveMap
    {
        public const byte NULL = 0;
        public const byte BOOLEAN_TYPE = 1;
        public const byte BYTE_TYPE = 2;
        public const byte CHAR_TYPE = 3;
        public const byte SHORT_TYPE = 4;
        public const byte INTEGER_TYPE = 5;
        public const byte LONG_TYPE = 6;
        public const byte DOUBLE_TYPE = 7;
        public const byte FLOAT_TYPE = 8;
        public const byte STRING_TYPE = 9;
        public const byte BYTE_ARRAY_TYPE = 10;
        public const byte MAP_TYPE = 11;
        public const byte LIST_TYPE = 12;
        public const byte BIG_STRING_TYPE = 13;

        private IDictionary dictionary = Hashtable.Synchronized(new Hashtable());

        public void Clear()
        {
            dictionary.Clear();
        }

        public bool Contains(Object key)
        {
            return dictionary.Contains(key);
        }

        public void Remove(Object key)
        {
            dictionary.Remove(key);
        }

        public int Count
        {
            get { return dictionary.Count; }
        }

        public ICollection Keys
        {
            get
            {
                lock (dictionary.SyncRoot) return new ArrayList(dictionary.Keys);
            }
        }

        public ICollection Values
        {
            get
            {
                lock (dictionary.SyncRoot) return new ArrayList(dictionary.Values);
            }
        }

        public object this[string key]
        {
            get { return GetValue(key); }
            set
            {
                CheckValidType(value);
                SetValue(key, value);
            }
        }

        public string GetString(string key)
        {
            Object value = GetValue(key);
            if (value == null)
            {
                return null;
            }

            CheckValueType(value, typeof(string));
            return (string) value;
        }

        public void SetString(string key, string value)
        {
            SetValue(key, value);
        }

        public bool GetBool(String key)
        {
            Object value = GetValue(key);
            CheckValueType(value, typeof(bool));
            return (bool) value;
        }

        public void SetBool(String key, bool value)
        {
            SetValue(key, value);
        }

        public byte GetByte(String key)
        {
            Object value = GetValue(key);
            CheckValueType(value, typeof(byte));
            return (byte) value;
        }

        public void SetByte(String key, byte value)
        {
            SetValue(key, value);
        }

        public char GetChar(String key)
        {
            Object value = GetValue(key);
            CheckValueType(value, typeof(char));
            return (char) value;
        }

        public void SetChar(String key, char value)
        {
            SetValue(key, value);
        }

        public short GetShort(String key)
        {
            Object value = GetValue(key);
            CheckValueType(value, typeof(short));
            return (short) value;
        }

        public void SetShort(String key, short value)
        {
            SetValue(key, value);
        }

        public int GetInt(String key)
        {
            Object value = GetValue(key);
            CheckValueType(value, typeof(int));
            return (int) value;
        }

        public void SetInt(String key, int value)
        {
            SetValue(key, value);
        }

        public long GetLong(String key)
        {
            Object value = GetValue(key);
            CheckValueType(value, typeof(long));
            return (long) value;
        }

        public void SetLong(String key, long value)
        {
            SetValue(key, value);
        }

        public float GetFloat(String key)
        {
            Object value = GetValue(key);
            CheckValueType(value, typeof(float));
            return (float) value;
        }

        public void SetFloat(String key, float value)
        {
            SetValue(key, value);
        }

        public double GetDouble(String key)
        {
            Object value = GetValue(key);
            CheckValueType(value, typeof(double));
            return (double) value;
        }

        public void SetDouble(String key, double value)
        {
            SetValue(key, value);
        }

        public IList GetList(String key)
        {
            Object value = GetValue(key);
            if (value != null && !(value is IList))
            {
                throw new NMSException("Property: " + key + " is not an IList but is: " + value);
            }

            return (IList) value;
        }

        public void SetList(String key, IList value)
        {
            SetValue(key, value);
        }

        public void SetBytes(String key, byte[] value)
        {
            this.SetBytes(key, value, 0, value.Length);
        }

        public void SetBytes(String key, byte[] value, int offset, int length)
        {
            byte[] copy = new byte[length];
            Array.Copy(value, offset, copy, 0, length);
            SetValue(key, copy);
        }

        public byte[] GetBytes(string key)
        {
            Object value = GetValue(key);
            if (value != null && !(value is Byte[]))
            {
                throw new NMSException("Property: " + key + " is not an byte[] but is: " + value);
            }

            return (byte[]) value;
        }

        public IDictionary GetDictionary(String key)
        {
            Object value = GetValue(key);
            if (value != null && !(value is IDictionary))
            {
                throw new NMSException("Property: " + key + " is not an IDictionary but is: " + value);
            }

            return (IDictionary) value;
        }

        public void SetDictionary(String key, IDictionary value)
        {
            SetValue(key, value);
        }

        protected virtual void SetValue(String key, Object value)
        {
            dictionary[key] = value;
        }

        protected virtual Object GetValue(String key)
        {
            return dictionary[key];
        }

        protected virtual void CheckValueType(Object value, Type type)
        {
            if (!type.IsInstanceOfType(value))
            {
                throw new NMSException("Expected type: " + type.Name + " but was: " + value);
            }
        }

        protected virtual void CheckValidType(Object value)
        {
            if (value != null && !(value is IList) && !(value is IDictionary))
            {
                Type type = value.GetType();

                if (type.IsInstanceOfType(typeof(Object)) ||
                    (!type.IsPrimitive && !type.IsValueType && !type.IsastignableFrom(typeof(string))))
                {
                    throw new NMSException("Invalid type: " + type.Name + " for value: " + value);
                }
            }
        }

        /// 
        /// Method ToString
        /// 
        /// A string
        public override String ToString()
        {
            String s = "{";
            bool first = true;
            lock (dictionary.SyncRoot)
            {
                foreach (DictionaryEntry entry in dictionary)
                {
                    if (!first)
                    {
                        s += ", ";
                    }

                    first = false;
                    String name = (String) entry.Key;
                    Object value = entry.Value;
                    s += name + "=" + value;
                }
            }

            s += "}";
            return s;
        }

        /// 
        /// Unmarshalls the map from the given data or if the data is null just
        /// return an empty map
        /// 
        public static PrimitiveMap Unmarshal(byte[] data)
        {
            PrimitiveMap answer = new PrimitiveMap();
            answer.dictionary = UnmarshalPrimitiveMap(data);
            return answer;
        }

        /// 
        /// Unmarshals a PrimitiveMap directly from a Stream object.  This 
        /// allows for clients to read PrimitiveMaps from Compressed or other
        /// wise encoded streams without this clast needing to know about it.
        /// 
        /// 
        /// A 
        /// 
        /// 
        /// A 
        /// 
        public static PrimitiveMap Unmarshal(Stream source)
        {
            PrimitiveMap answer = new PrimitiveMap();
            answer.dictionary = UnmarshalPrimitiveMap(source);
            return answer;
        }

        public byte[] Marshal()
        {
            lock (dictionary.SyncRoot)
            {
                return MarshalPrimitiveMap(dictionary);
            }
        }

        /// 
        /// Marshals a PrimitiveMap directly to a Stream object.  This
        /// allows a client to write a PrimitiveMap in a compressed or 
        /// otherwise encoded form without this clast needing to know 
        /// about it.
        /// 
        /// 
        /// A 
        /// 
        public void Marshal(Stream destination)
        {
            lock (dictionary.SyncRoot)
            {
                MarshalPrimitiveMap(dictionary, destination);
            }
        }

        /// 
        /// Marshals the primitive type map to a byte array
        /// 
        public static byte[] MarshalPrimitiveMap(IDictionary map)
        {
            if (map == null)
            {
                return null;
            }

            MemoryStream memoryStream = new MemoryStream();
            lock (map.SyncRoot)
            {
                MarshalPrimitiveMap(map, new EndianBinaryWriter(memoryStream));
            }

            return memoryStream.ToArray();
        }

        public static void MarshalPrimitiveMap(IDictionary map, Stream stream)
        {
            if (map != null)
            {
                lock (map.SyncRoot)
                {
                    MarshalPrimitiveMap(map, new EndianBinaryWriter(stream));
                }
            }
        }

        public static void MarshalPrimitiveMap(IDictionary map, BinaryWriter dataOut)
        {
            if (map == null)
            {
                dataOut.Write((int) -1);
            }
            else
            {
                lock (map.SyncRoot)
                {
                    dataOut.Write(map.Count);
                    foreach (DictionaryEntry entry in map)
                    {
                        String name = (String) entry.Key;
                        dataOut.Write(name);
                        Object value = entry.Value;
                        MarshalPrimitive(dataOut, value);
                    }
                }
            }
        }

        /// 
        /// Unmarshals the primitive type map from the given byte array
        /// 
        public static IDictionary UnmarshalPrimitiveMap(byte[] data)
        {
            if (data == null)
            {
                return new Hashtable();
            }
            else
            {
                return UnmarshalPrimitiveMap(new EndianBinaryReader(new MemoryStream(data)));
            }
        }

        public static IDictionary UnmarshalPrimitiveMap(Stream source)
        {
            return UnmarshalPrimitiveMap(new EndianBinaryReader(source));
        }

        public static IDictionary UnmarshalPrimitiveMap(BinaryReader dataIn)
        {
            int size = dataIn.ReadInt32();
            if (size < 0)
            {
                return null;
            }

            IDictionary answer = new Hashtable(size);
            for (int i = 0; i < size; i++)
            {
                String name = dataIn.ReadString();
                answer[name] = UnmarshalPrimitive(dataIn);
            }

            return answer;
        }

        public static void MarshalPrimitiveList(IList list, BinaryWriter dataOut)
        {
            dataOut.Write((int) list.Count);
            foreach (Object element in list)
            {
                MarshalPrimitive(dataOut, element);
            }
        }

        public static IList UnmarshalPrimitiveList(BinaryReader dataIn)
        {
            int size = dataIn.ReadInt32();
            IList answer = new ArrayList(size);
            while (size-- > 0)
            {
                answer.Add(UnmarshalPrimitive(dataIn));
            }

            return answer;
        }

        public static void MarshalPrimitive(BinaryWriter dataOut, Object value)
        {
            if (value == null)
            {
                dataOut.Write(NULL);
            }
            else if (value is bool)
            {
                dataOut.Write(BOOLEAN_TYPE);
                dataOut.Write((bool) value);
            }
            else if (value is byte)
            {
                dataOut.Write(BYTE_TYPE);
                dataOut.Write(((byte) value));
            }
            else if (value is char)
            {
                dataOut.Write(CHAR_TYPE);
                dataOut.Write((char) value);
            }
            else if (value is short)
            {
                dataOut.Write(SHORT_TYPE);
                dataOut.Write((short) value);
            }
            else if (value is int)
            {
                dataOut.Write(INTEGER_TYPE);
                dataOut.Write((int) value);
            }
            else if (value is long)
            {
                dataOut.Write(LONG_TYPE);
                dataOut.Write((long) value);
            }
            else if (value is float)
            {
                dataOut.Write(FLOAT_TYPE);
                dataOut.Write((float) value);
            }
            else if (value is double)
            {
                dataOut.Write(DOUBLE_TYPE);
                dataOut.Write((double) value);
            }
            else if (value is byte[])
            {
                byte[] data = (byte[]) value;
                dataOut.Write(BYTE_ARRAY_TYPE);
                dataOut.Write(data.Length);
                dataOut.Write(data);
            }
            else if (value is string)
            {
                string s = (string) value;
                // is the string big??
                if (s.Length > 8191)
                {
                    dataOut.Write(BIG_STRING_TYPE);
                    ((EndianBinaryWriter) dataOut).WriteString32(s);
                }
                else
                {
                    dataOut.Write(STRING_TYPE);
                    ((EndianBinaryWriter) dataOut).WriteString16(s);
                }
            }
            else if (value is IDictionary)
            {
                dataOut.Write(MAP_TYPE);
                MarshalPrimitiveMap((IDictionary) value, dataOut);
            }
            else if (value is IList)
            {
                dataOut.Write(LIST_TYPE);
                MarshalPrimitiveList((IList) value, dataOut);
            }
            else
            {
                throw new IOException("Object is not a primitive: " + value);
            }
        }

        public static Object UnmarshalPrimitive(BinaryReader dataIn)
        {
            Object value = null;
            byte type = dataIn.ReadByte();
            switch (type)
            {
                case NULL:
                    value = null;
                    break;
                case BYTE_TYPE:
                    value = dataIn.ReadByte();
                    break;
                case BOOLEAN_TYPE:
                    value = dataIn.ReadBoolean();
                    break;
                case CHAR_TYPE:
                    value = dataIn.ReadChar();
                    break;
                case SHORT_TYPE:
                    value = dataIn.ReadInt16();
                    break;
                case INTEGER_TYPE:
                    value = dataIn.ReadInt32();
                    break;
                case LONG_TYPE:
                    value = dataIn.ReadInt64();
                    break;
                case FLOAT_TYPE:
                    value = dataIn.ReadSingle();
                    break;
                case DOUBLE_TYPE:
                    value = dataIn.ReadDouble();
                    break;
                case BYTE_ARRAY_TYPE:
                    int size = dataIn.ReadInt32();
                    byte[] data = new byte[size];
                    dataIn.Read(data, 0, size);
                    value = data;
                    break;
                case STRING_TYPE:
                    value = ((EndianBinaryReader) dataIn).ReadString16();
                    break;
                case BIG_STRING_TYPE:
                    value = ((EndianBinaryReader) dataIn).ReadString32();
                    break;
                case MAP_TYPE:
                    value = UnmarshalPrimitiveMap(dataIn);
                    break;
                case LIST_TYPE:
                    value = UnmarshalPrimitiveList(dataIn);
                    break;

                default:
                    throw new Exception("Unsupported data type: " + type);
            }

            return value;
        }
    }
}