blob: e62cfa1b6e03dd91404f9bd6da7bf8eb98394213 [file] [log] [blame]
/*
* 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
{
/// <summary>
/// A default implementation of IPrimitiveMap
/// </summary>
public class 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.IsAssignableFrom(typeof(string))))
{
throw new NMSException("Invalid type: " + type.Name + " for value: " + value);
}
}
}
/// <summary>
/// Method ToString
/// </summary>
/// <returns>A string</returns>
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;
}
/// <summary>
/// Unmarshalls the map from the given data or if the data is null just
/// return an empty map
/// </summary>
public static PrimitiveMap Unmarshal(byte[] data)
{
PrimitiveMap answer = new PrimitiveMap();
answer.dictionary = UnmarshalPrimitiveMap(data);
return answer;
}
/// <summary>
/// Unmarshals a PrimitiveMap directly from a Stream object. This
/// allows for clients to read PrimitiveMaps from Compressed or other
/// wise encoded streams without this class needing to know about it.
/// </summary>
/// <param name="source">
/// A <see cref="Stream"/>
/// </param>
/// <returns>
/// A <see cref="PrimitiveMap"/>
/// </returns>
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);
}
}
/// <summary>
/// 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 class needing to know
/// about it.
/// </summary>
/// <param name="destination">
/// A <see cref="Stream"/>
/// </param>
public void Marshal(Stream destination)
{
lock(dictionary.SyncRoot)
{
MarshalPrimitiveMap(dictionary, destination);
}
}
/// <summary>
/// Marshals the primitive type map to a byte array
/// </summary>
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);
}
}
}
}
/// <summary>
/// Unmarshals the primitive type map from the given byte array
/// </summary>
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;
}
}
}