//
//
//
//
// $Revision: 2564 $
//
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Xml;
namespace ICSharpCode.Core
{
public class Runtime
{
string hintPath;
string assembly;
Assembly loadedAssembly = null;
IList definedDoozers = new List();
IList definedConditionEvaluators = new List();
ICondition[] conditions;
bool isActive = true;
bool isAssemblyLoaded;
public bool IsActive {
get {
if (conditions != null) {
isActive = Condition.GetFailedAction(conditions, this) == ConditionFailedAction.Nothing;
conditions = null;
}
return isActive;
}
}
public Runtime(string assembly, string hintPath)
{
this.assembly = assembly;
this.hintPath = hintPath;
}
public string Assembly {
get {
return assembly;
}
}
///
/// Force loading the runtime assembly now.
///
public void Load()
{
if (!isAssemblyLoaded) {
LoggingService.Info("Loading addin " + assembly);
isAssemblyLoaded = true;
try {
if (assembly[0] == ':') {
loadedAssembly = System.Reflection.Assembly.Load(assembly.Substring(1));
} else if (assembly[0] == '$') {
int pos = assembly.IndexOf('/');
if (pos < 0)
throw new ApplicationException("Expected '/' in path beginning with '$'!");
string referencedAddIn = assembly.Substring(1, pos - 1);
foreach (AddIn addIn in AddInTree.AddIns) {
if (addIn.Enabled && addIn.Manifest.Identities.ContainsKey(referencedAddIn)) {
string assemblyFile = Path.Combine(Path.GetDirectoryName(addIn.FileName),
assembly.Substring(pos + 1));
loadedAssembly = System.Reflection.Assembly.LoadFrom(assemblyFile);
break;
}
}
if (loadedAssembly == null) {
throw new FileNotFoundException("Could not find referenced AddIn " + referencedAddIn);
}
} else {
loadedAssembly = System.Reflection.Assembly.LoadFrom(Path.Combine(hintPath, assembly));
}
#if DEBUG
// preload assembly to provoke FileLoadException if dependencies are missing
loadedAssembly.GetExportedTypes();
#endif
} catch (FileNotFoundException ex) {
MessageService.ShowError("The addin '" + assembly + "' could not be loaded:\n" + ex.ToString());
} catch (FileLoadException ex) {
MessageService.ShowError("The addin '" + assembly + "' could not be loaded:\n" + ex.ToString());
}
}
}
public Assembly LoadedAssembly {
get {
Load(); // load the assembly, if not already done
return loadedAssembly;
}
}
public IList DefinedDoozers {
get {
return definedDoozers;
}
}
public IList DefinedConditionEvaluators {
get {
return definedConditionEvaluators;
}
}
public object CreateInstance(string instance)
{
if (IsActive) {
Assembly asm = LoadedAssembly;
if (asm == null)
return null;
return asm.CreateInstance(instance);
} else {
return null;
}
}
internal static void ReadSection(XmlReader reader, AddIn addIn, string hintPath)
{
Stack conditionStack = new Stack();
while (reader.Read()) {
switch (reader.NodeType) {
case XmlNodeType.EndElement:
if (reader.LocalName == "Condition" || reader.LocalName == "ComplexCondition") {
conditionStack.Pop();
} else if (reader.LocalName == "Runtime") {
return;
}
break;
case XmlNodeType.Element:
switch (reader.LocalName) {
case "Condition":
conditionStack.Push(Condition.Read(reader));
break;
case "ComplexCondition":
conditionStack.Push(Condition.ReadComplexCondition(reader));
break;
case "Import":
addIn.Runtimes.Add(Runtime.Read(addIn, reader, hintPath, conditionStack));
break;
case "DisableAddIn":
if (Condition.GetFailedAction(conditionStack, addIn) == ConditionFailedAction.Nothing) {
// The DisableAddIn node not was not disabled by a condition
addIn.CustomErrorMessage = reader.GetAttribute("message");
}
break;
default:
throw new AddInLoadException("Unknown node in runtime section :" + reader.LocalName);
}
break;
}
}
}
internal static Runtime Read(AddIn addIn, XmlReader reader, string hintPath, Stack conditionStack)
{
if (reader.AttributeCount != 1) {
throw new AddInLoadException("Import node requires ONE attribute.");
}
Runtime runtime = new Runtime(reader.GetAttribute(0), hintPath);
if (conditionStack.Count > 0) {
runtime.conditions = conditionStack.ToArray();
}
if (!reader.IsEmptyElement) {
while (reader.Read()) {
switch (reader.NodeType) {
case XmlNodeType.EndElement:
if (reader.LocalName == "Import") {
return runtime;
}
break;
case XmlNodeType.Element:
string nodeName = reader.LocalName;
Properties properties = Properties.ReadFromAttributes(reader);
switch (nodeName) {
case "Doozer":
if (!reader.IsEmptyElement) {
throw new AddInLoadException("Doozer nodes must be empty!");
}
runtime.definedDoozers.Add(new LazyLoadDoozer(addIn, properties));
break;
case "ConditionEvaluator":
if (!reader.IsEmptyElement) {
throw new AddInLoadException("ConditionEvaluator nodes must be empty!");
}
runtime.definedConditionEvaluators.Add(new LazyConditionEvaluator(addIn, properties));
break;
default:
throw new AddInLoadException("Unknown node in Import section:" + nodeName);
}
break;
}
}
}
runtime.definedDoozers = (runtime.definedDoozers as List).AsReadOnly();
runtime.definedConditionEvaluators = (runtime.definedConditionEvaluators as List).AsReadOnly();
return runtime;
}
}
}