/*
OpenNxSerialization Framework
Copyright (C) 2006 - 2008 "NeXtreme Innovations"
[The Next Xtreme Innovations]
This program is free software, distributed under the terms of
the GNU General Public License Version 2. See the "License.txt" file
at the top of the source tree.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace NeXtreme.OpenNxSerialization.IO
{
/// <summary>
/// A class that maintains serialization/deserialization context. This is used to
/// resolve circular and shared references.
/// </summary>
public class NxSerializationContext
{
private INxTypeSurrogateSelector mSurrogateSelector;
private IFormatterConverter mConverter = new FormatterConverter();
private StreamingContext mStreamContext = new StreamingContext(StreamingContextStates.All);
private SerializationBinder mBinder = null;
private ISurrogateSelector mNativeSurrogateSelector = null;
private IDictionary mUserItems = new Hashtable();
/*
* ISSUE: Using an ArrayList to maintain context doubles the prformance but for
* small number of objects only. This is good if there arent any containers, but as
* the number of objects grow a hashtable performs much better.
*
* TODO: Come up with a structure that performs neraly linearly in most situations.
*/
/// <summary> Represents a list of objects known in the context so far. </summary>
private ArrayList mGraphList = new ArrayList();
private Dictionary<object, int> mCookieList = new Dictionary<object, int>();
/// <summary> Represents an invalid cookie value </summary>
public const int INVALID_COOKIE = -1;
/// <summary>
/// Constructor
/// </summary>
public NxSerializationContext()
{
this.mSurrogateSelector = NxTypeSurrogateSelector.Default;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="surrogateSelector"></param>
public NxSerializationContext(INxTypeSurrogateSelector surrogateSelector)
{
this.mSurrogateSelector = surrogateSelector;
}
/// <summary>
/// Returns the associated <see cref="INxTypeSurrogateSelector"/> instance.
/// </summary>
public INxTypeSurrogateSelector SurrogateSelector
{
get { return mSurrogateSelector; }
}
/// <summary>
/// Gets or sets the <see cref="ISurrogateSelector"/> used by the current formatter
/// </summary>
public ISurrogateSelector NativeSurrogateSelector
{
get { return mNativeSurrogateSelector; }
set { mNativeSurrogateSelector = value; }
}
/// <summary>
/// Gets or sets the <see cref="SerializationBinder"/> that performs type lookups during deserialization
/// </summary>
public SerializationBinder Binder
{
get { return mBinder; }
set { mBinder = value; }
}
/// <summary>
/// Get/Set the <see cref="IFormatterConverter"/> object associated with the current context.
/// </summary>
[CLSCompliant(false)]
public IFormatterConverter FormatConverter
{
get { return mConverter; }
set { mConverter = value; }
}
/// <summary>
/// Get/Set the <see cref="StreamingContext"/> object associated with the current context.
/// </summary>
public StreamingContext StreamingContext
{
get { return mStreamContext; }
set { mStreamContext = value; }
}
/// <summary>
/// Gets or sets the user value associated with the specified key
/// </summary>
/// <param name="key">The key whose value to get or set</param>
/// <value>The value associated with the specified key. If the specified key is
/// not found, attempting to get it returns a null reference, and
/// attempting to set it creates a new element using the specified key.</value>
public object this[object key]
{
get { return mUserItems[key]; }
set { mUserItems[key] = value; }
}
/// <summary>
/// Resets this instance of <see cref="NxSerializationContext"/>.
/// </summary>
public void Clear()
{
mGraphList = new ArrayList();
mCookieList = new Dictionary<object, int>();
mUserItems.Clear();
}
/// <summary>
/// Returns cookie for a given graph.
/// </summary>
/// <param name="graph"></param>
/// <returns></returns>
public int GetCookie(object graph)
{
if(mCookieList.ContainsKey(graph))
return (int)mCookieList[graph];
return INVALID_COOKIE;
}
/// <summary>
/// Returns a graph by its cookie. If there is no such cookie null is returned.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public object GetObject(int key)
{
if (key > NxSerializationContext.INVALID_COOKIE && key < mGraphList.Count)
return mGraphList[key];
return null;
}
/// <summary>
/// Adds a graph to the context, assigns a cookie to it.
/// Currently the index of the graph is its cookie.
/// </summary>
public int RememberForRead(object graph)
{
int cookie = mGraphList.Count;
mGraphList.Add(graph);
return cookie;
}
/// <summary>
/// Adds a graph to the context, assigns a cookie to it.
/// Currently the index of the graph is its cookie.
/// </summary>
public int RememberForWrite(object graph)
{
int cookie = mCookieList.Count;
mCookieList[graph] = cookie;
return cookie;
}
}
}