#region Information
/*
by Petro Protsyk
28.11.2008, 22:16
*/
#endregion
#region using
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Xml.Serialization;
using ScriptNET.Runtime.Configuration;
using ScriptNET.Runtime.Operators;
#if SILVERLIGHT || PocketPC
using DefaultAssemblyManager = ScriptNET.Runtime.BaseAssemblyManager;
using DefaultActivator = ScriptNET.Runtime.ObjectActivator;
using DefaultBinder = ScriptNET.Runtime.ObjectBinderExtended;
#else
using DefaultAssemblyManager = ScriptNET.Runtime.AssemblyManager;
using DefaultActivator = ScriptNET.Runtime.ObjectActivator;
using DefaultBinder = ScriptNET.Runtime.ObjectBinderExtended;
#endif
#endregion
namespace ScriptNET.Runtime
{
///
/// Run-time configuration manager for Script.net
///
public static class RuntimeHost
{
#region Fields
private static ScriptConfiguration Configuration = null;
private static Script InitializationScript = null;
///
/// Settings section
///
private static readonly Dictionary SettingsItems = new Dictionary();
///
/// Operators
///
private static readonly Dictionary BinOperators = new Dictionary();
///
/// Operators
///
private static readonly Dictionary UnaryOperators = new Dictionary();
///
/// Object used to synchronize during multi-threaded execution
///
private static object syncRoot = new object();
[Bindable(false)]
public static IScopeFactory ScopeFactory {get; private set;}
public static IObjectBinder Binder { get; set; }
[Bindable(false)]
public static IAssemblyManager AssemblyManager { get; set; }
///
/// Activator which used to activate instances
///
public static IObjectActivator Activator { get; set; }
private static readonly Dictionary Handlers = new Dictionary();
///
/// Should be returned by GetVariableInternal if item with given
/// name not found in the scope hierarchy
///
public static object NoVariable = new object();
public static object NullValue = new object();
#endregion
#region Construction & Initialization
///
/// Load default configuration from RuntimeConfig.xml
///
[Bindable(false)]
public static void Initialize()
{
Initialize(DefaultConfig);
}
///
/// Loads given configuration
///
///
[Bindable(false)]
public static void Initialize(Stream configuration)
{
Lock();
try
{
LoadConfiguration(configuration);
if (Binder == null)
{
Binder = new DefaultBinder();
}
if (Activator == null)
{
Activator = new DefaultActivator();
}
InitializeSettingItems();
RegisterOperators();
if (ScopeFactory == null)
{
ScopeFactory = Activator.CreateInstance(GetNativeType(GetSettingsItem(ConfigSchema.ScopeFactoryAttribute))) as IScopeFactory;
}
RegisterScopes();
if (AssemblyManager == null)
{
AssemblyManager = new DefaultAssemblyManager();
}
OnInitializingTypes(AssemblyManager);
AssemblyManager.Initialize(Configuration);
if (!string.IsNullOrEmpty(Configuration.Initialization))
InitializationScript = Script.Compile(Configuration.Initialization);
RegisterOperatorHandler("+=", new EventOperatorHandler(true));
RegisterOperatorHandler("-=", new EventOperatorHandler(false));
ScriptNET.Ast.ScriptExpr.HandleOperator += HandleOperator;
}
finally
{
UnLock();
}
}
private static void RegisterOperators()
{
foreach (OperatorDefinition definition in Configuration.Operators)
{
IOperator oper = (IOperator)Activator.CreateInstance(GetNativeType(definition.Type));
if (oper.Unary)
UnaryOperators.Add(oper.Name, oper);
else
BinOperators.Add(oper.Name, oper);
}
}
private static void HandleOperator(object sender, HandleOperatorArgs e)
{
if (Handlers.ContainsKey(e.Symbol))
{
e.Result = Handlers[e.Symbol].Process(e);
}
}
private static void RegisterScopes()
{
//NOTE: Default values
//ScopeFactory.RegisterType(ScopeTypes.Default, typeof(ScriptScope));
//ScopeFactory.RegisterType(ScopeTypes.Contract, typeof(ScriptContractScope));
//ScopeFactory.RegisterType(ScopeTypes.Using, typeof(ScriptUsingScope));
foreach (ScopeDefinition definition in Configuration.Scopes)
{
ScopeFactory.RegisterType(definition.Id, (IScopeActivator)Activator.CreateInstance(GetNativeType(definition.Type)));
}
}
///
/// Clears all information in the RuntimeHost
///
[Bindable(false)]
public static void CleanUp()
{
Lock();
try
{
ScriptNET.Ast.ScriptExpr.HandleOperator -= HandleOperator;
Handlers.Clear();
initializingTypes.Clear();
Binder = null;
Activator = null;
ScopeFactory = null;
if (AssemblyManager != null)
AssemblyManager.Dispose();
AssemblyManager = null;
SettingsItems.Clear();
BinOperators.Clear();
UnaryOperators.Clear();
InitializationScript = null;
Configuration = new ScriptConfiguration();
}
finally
{
UnLock();
}
}
#endregion
#region Methods
///
/// Loads language configuration from stream
///
///
private static void LoadConfiguration(Stream configStream)
{
XmlSerializer configurationSerializer = new XmlSerializer(typeof(ScriptConfiguration));
Configuration = configurationSerializer.Deserialize(configStream) as ScriptConfiguration;
if (Configuration == null)
throw new ScriptException("Configuration has wrong format or empty");
}
#endregion
#region Loading
private static void InitializeSettingItems()
{
foreach (SettingXml item in Configuration.SettingXml)
{
object rez = item.Value;
if (!string.IsNullOrEmpty(item.Converter))
rez = GetItemValue(item.Value, item.Converter);
SettingsItems.Add(item.Name, rez);
}
}
private static object GetItemValue(string value, string converter)
{
Type converterType = GetNativeType(converter);
#if PocketPC || SILVERLIGHT
try
{
return Convert.ChangeType(value, converterType, System.Globalization.CultureInfo.InvariantCulture);
}
catch
{
System.Diagnostics.Debug.WriteLine("Failed to convert string to type: " + converterType.ToString());
}
#else
TypeConverter converterObject = Activator.CreateInstance(converterType) as TypeConverter;
if (converterObject != null && converterObject.CanConvertFrom(typeof(string)))
{
return converterObject.ConvertFrom(value);
}
#endif
return value;
}
#endregion
#region Public methods
///
/// Returns setting item specified in run-time config file
///
///
///
public static object GetSettingsItem(string id)
{
if (SettingsItems.ContainsKey(id))
return SettingsItems[id];
return null;
}
public static void SetSettingItem(string id, object value)
{
Lock();
try
{
if (SettingsItems.ContainsKey(id))
{
SettingsItems[id] = value;
}
else
{
SettingsItems.Add(id, value);
}
}
finally
{
UnLock();
}
}
///
/// Returns setting item specified in run-time config file
///
///
///
public static T GetSettingsItem(string id)
{
object result = GetSettingsItem(id);
return result == null ? default(T) : (T)result;
}
[Bindable(false)]
public static IOperator GetBinaryOperator(string id)
{
if (!BinOperators.ContainsKey(id))
throw new NotSupportedException(string.Format("Given operator {0} is not found", id));
return BinOperators[id];
}
[Bindable(false)]
public static IOperator GetUnaryOperator(string id)
{
if (!UnaryOperators.ContainsKey(id))
throw new NotSupportedException(string.Format("Given operator {0} is not found", id));
return UnaryOperators[id];
}
[Bindable(false)]
public static void InitializeScript(IScriptContext context)
{
if (InitializationScript == null) return;
Lock();
InitializationScript.Context = context;
InitializationScript.Execute();
InitializationScript.Context = null;
UnLock();
}
internal static Type GetNativeType(string name)
{
return Type.GetType(name);
}
public static Type GetType(string name)
{
return AssemblyManager.GetType(name);
}
public static bool HasType(string name)
{
return AssemblyManager.HasType(name);
}
[Bindable(false)]
public static void AddType(string alias, Type type)
{
AssemblyManager.AddType(alias, type);
}
[Bindable(false)]
public static void RegisterOperatorHandler(string operatorSymbol, IOperatorHandler handler)
{
if (!Handlers.ContainsKey(operatorSymbol))
Handlers.Add(operatorSymbol, handler);
else
Handlers[operatorSymbol] = handler;
}
///
/// Lock's runtime host for threading execution
///
public static void Lock()
{
Monitor.Enter(syncRoot);
}
///
/// Unlock's thread
///
public static void UnLock()
{
Monitor.Exit(syncRoot);
}
///
/// This event is raised before AssemblyManager starts creating type system.
/// It should be used to subscribe on AssemblyManager's events in order to cancel
/// loading some assemblies and adding particular types
///
public static event EventHandler InitializingTypes
{
add
{
initializingTypes.Add(value);
}
remove
{
initializingTypes.Remove(value);
}
}
private static List> initializingTypes = new List>();
private static void OnInitializingTypes(object sender)
{
foreach (EventHandler handler in initializingTypes)
handler.Invoke(sender, EventArgs.Empty);
}
#endregion
#region Config
public static Stream DefaultConfig
{
get
{
Stream configStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("FiestaShark.ScriptDotNet.RuntimeConfig.xml");
configStream.Seek(0, SeekOrigin.Begin);
return configStream;
}
}
#endregion
}
}