/* * public void Load(AppDomain AppDomain, string AppDomainName, string PathToAssembly) * { * if (Disposed) * return; * * if (IsLoaded || asm != null) * throw new Exception("Load() was already executed"); * * this.AppDomain = AppDomain; * this.PathToAssembly = PathToAssembly; * this.AppDomainName = AppDomainName; * * asm = Assembly.Load(AssemblyName.GetAssemblyName(this.PathToAssembly)); * * IsLoaded = true; * } * * public void Run() * { * if (Disposed) * return; * * if (!IsLoaded) * throw new Exception("Load() must be executed before Run()"); * * * //var t = asm.GetTypes().First(x => x.FullName.Equals(WorkerClassName)); * //BatchFoundation.Worker.Worker w = (BatchFoundation.Worker.Worker)Activator.CreateInstance(t); * //w.Run(Input, Output, ref data); * } * * public static void Init() * { * if (!isInit) * lock (wlsync) * { * if (!isInit) * { * ForemanIdToLoader = new ConcurrentDictionary<string, ForemanLoader>(); * isInit = true; * } * } * } * * public static ForemanLoader RegisterInstance(string PathToConfigFile) * { * if (!isInit) * Init(); * * if (AppDomainName == null) * throw new ArgumentNullException("AppDomainName"); * * if (PathToAssembly == null) * throw new ArgumentNullException("PathToAssembly"); * * // check that there isn't an app domain already for this name and path * ForemanLoader wl, wlAppDomain, wlPath; * * bool isAppDomain = AppDomainToWorkerLoader.TryGetValue(AppDomainName, out wlAppDomain); * bool isPathToAssembly = AssemblyPathToWorkerLoader.TryGetValue(PathToAssembly, out wlPath); * * if (isAppDomain && isPathToAssembly) * { * // both found * wl = wlAppDomain; * } * else if (isAppDomain && !isPathToAssembly) * { * // another path was found with the same app domain name * throw new Exception("Cannot declare two assemblies with the same name but different paths"); * } * else if (!isAppDomain && isPathToAssembly) * { * // another app domain was found with the same path * throw new Exception("Cannot declare two assemblies with the same path but different names"); * //AppDomainToWorkerLoader.AddOrUpdate(AppDomainName, wlPath, (k, v) => wlPath); * //wl = wlPath; * } * else * { * // both not found so create new and don't forget to Load() * AppDomain ad = AppDomain.CreateDomain(AppDomainName); * * wl = (ForemanLoader)ad.CreateInstanceAndUnwrap(typeof(ForemanLoader).Assembly.FullName, typeof(ForemanLoader).FullName); * wl.Load(ad, AppDomainName, PathToAssembly); * * AppDomainToWorkerLoader.AddOrUpdate(AppDomainName, wl, (k, v) => wl); * AssemblyPathToWorkerLoader.AddOrUpdate(PathToAssembly, wl, (k, v) => wl); * * * //int x = 1; * //object o = (object)x; * //wl.Run("BatchTest.Test2.MyWorker2", null, null, ref o); * //Console.WriteLine(o); * //Console.ReadLine(); * * } * * return wl; * } * * public static bool TryGetInstanceByAppDomainName(string AppDomainName, out ForemanLoader wl) * { * return AppDomainToWorkerLoader.TryGetValue(AppDomainName, out wl); * } * * public static bool TryGetInstanceByPathToAssembly(string PathToAssembly, out ForemanLoader wl) * { * return AssemblyPathToWorkerLoader.TryGetValue(PathToAssembly, out wl); * } * * public static void UnloadByAppDomainName(string AppDomainName) * { * // first check that this assembly is never used in current configs! * * ForemanLoader wlAppDomain, wlPath; * * AppDomainToWorkerLoader.TryRemove(AppDomainName, out wlAppDomain); * * if (wlAppDomain != null) * { * AssemblyPathToWorkerLoader.TryRemove(wlAppDomain.PathToAssembly, out wlPath); * wlAppDomain.Dispose(); * wlPath.Dispose(); * } * } * * public static void UnloadByPathToAssembly(string PathToAssembly) * { * // first check that this assembly is never used in current configs! * * ForemanLoader wlAppDomain, wlPath; * * AssemblyPathToWorkerLoader.TryRemove(PathToAssembly, out wlPath); * * if (wlPath != null) * { * AppDomainToWorkerLoader.TryRemove(wlPath.AppDomainName, out wlAppDomain); * wlAppDomain.Dispose(); * wlPath.Dispose(); * } * } */ public static ForemanLoader CreateInstance(string ForemanId, string ConfigString, ForemanConfigurationFile Config = null, ContractorSettings ContractorSettings = null) { if (Config == null) { Config = ForemanBase.ParseAndLoadConfigString(ForemanId, ConfigString, ContractorSettings); } var baseDir = Path.GetDirectoryName(Config.assemblyPath); AppDomainSetup setup = new AppDomainSetup(); setup.ApplicationBase = baseDir; AppDomain ad = AppDomain.CreateDomain(Guid.NewGuid().ToString(), AppDomain.CurrentDomain.Evidence, setup); //AppDomain ad = AppDomain.CreateDomain(Guid.NewGuid().ToString()); ForemanLoader fl = null; //try //{ fl = (ForemanLoader)ad.CreateInstanceAndUnwrap(typeof(ForemanLoader).Assembly.FullName, typeof(ForemanLoader).FullName); //fl = new ForemanLoader(); //} //catch (Exception ex) //{ // Console.WriteLine(ex.Message); //} if (ContractorSettings == null) { ContractorSettings = new ContractorSettings(); } fl.Id = ForemanId; fl.AppDomain = ad; fl.ConfigString = ConfigString; fl.ContractorSettings = ContractorSettings; fl.Config = Config; fl.Load(); return(fl); }
public static ForemanConfigurationFile ParseAndLoadConfigString(string ForemanId, string ConfigString, ContractorSettings ContractorSettings) { ForemanConfigurationFile Config; try { Config = JsonConvert.DeserializeObject <ForemanConfigurationFile>(ConfigString); } catch (Exception ex) { string err = "Can't parse config string (" + ex.Message + ")"; throw new Exception(err, ex); } if (Config.assemblyPath == null || Config.assemblyPath.Length == 0) { throw new Exception("assemblyPath field in Foreman configuration file cannot be empty"); } if (!Path.IsPathRooted(Config.assemblyPath)) { if (ContractorSettings.ForemanFetchDLLBaseDir == null) { throw new Exception("if the assemblyPath field is a relative path then ContractorSettings.ForemanDllBaseDir must be defined"); } Config.assemblyPath = Path.Combine(ContractorSettings.ForemanFetchDLLBaseDir, Config.assemblyPath); } if (!File.Exists(Config.assemblyPath)) { throw new Exception("assemblyPath not a real file"); } if (ContractorSettings.IsKeepLocalForemanDLL) { // copy file locally if (ContractorSettings.IsKeepLocalForemanDLL && ContractorSettings.ForemanLocalDLLBaseDir == null) { throw new Exception("Storing a local copy of the Foremen DLL is set to true but local DLL base dir is not defined"); } string destPath = Path.Combine(ContractorSettings.ForemanLocalDLLBaseDir, "frmn_" + ForemanId); Directory.CreateDirectory(destPath); string destFile = Path.Combine(destPath, Path.GetFileName(Config.assemblyPath)); // will throw if the local file exists and in use if (!ContractorSettings.IsOverwriteLocalForemanDLL && File.Exists(destFile)) { throw new Exception("Local Foreman DLL file already exists so clear local cache or allow local overwrite"); } File.Copy(Config.assemblyPath, destFile, ContractorSettings.IsOverwriteLocalForemanDLL); Config.assemblyPath = destFile; } return(Config); }
public void Load() { if (IsDisposed) { return; } if (IsLoaded) { throw new Exception("Foreman already loaded"); } if (IsRunning) { return; } if (ConfigString == null && Config == null) { throw new ArgumentNullException("ConfigString"); } if (ContractorSettings == null) { ContractorSettings = new ContractorSettings(); } // load config file only if not already defined by Contractor if (Config == null) { Config = ParseAndLoadConfigString(Id, ConfigString, ContractorSettings); } int NodeCounter = 0; int QueueCounter = 0; IsNodesLongRunning = Config.isNodesLongRunning; // register assembly asm = Assembly.LoadFile(Config.assemblyPath); // loading an app domain solves the referenced assemblies problem? /* * AssemblyName[] ReferencedAssemblies = asm.GetReferencedAssemblies(); * foreach (var refAsm in ReferencedAssemblies) * if (refAsm != null) * Assembly.Load(refAsm); */ // Register nodes if (Config.nodes == null || Config.nodes.Count == 0) { throw new ArgumentException("No nodes in config file"); } nodes = new WorkerNode[Config.nodes.Count]; workerNodeExeOrder = new Dictionary <int, List <WorkerNode> >(); nodeNameToId = new Dictionary <string, int>(Config.nodes.Count); foreach (var configNode in Config.nodes) { var node = new WorkerNode(); node.Id = NodeCounter; node.OrderId = configNode.exeOrderId; node.Name = configNode.name; node.WorkerClassName = configNode.className; var workerType = asm.GetTypes().First(x => x.FullName.Equals(configNode.className)); if (workerType == null) { throw new Exception("Type not found: " + configNode.className); } var worker = (WorkerBase)Activator.CreateInstance(workerType); if (worker == null) { throw new Exception("Can't create instance from" + configNode.className); } node.Worker = worker; if (!workerNodeExeOrder.ContainsKey(node.OrderId)) { workerNodeExeOrder.Add(node.OrderId, new List <WorkerNode>() { node }); } else { workerNodeExeOrder[node.OrderId].Add(node); } node.State = WorkerNodeState.Idle; nodes[NodeCounter] = node; nodeNameToId.Add(node.Name, node.Id); NodeCounter++; } // Register queues if (Config.queues == null || Config.queues.Count == 0) { Config.queues = new List <FCFQueue>(); } if (Config.queues.Count > 0 && !IsNodesLongRunning) { throw new Exception("Can't define queues in short running foremen"); } queues = new BlockingCollection <object> [Config.queues.Count]; queueNameToId = new Dictionary <string, int>(Config.queues.Count); //queueIsToEl = new bool[config.queues.Count]; //queueIsFromEl = new bool[config.queues.Count]; foreach (var configQueue in Config.queues) { if (queueNameToId.ContainsKey(configQueue.name)) { string err = "The queue name '" + configQueue.name + "' is already registered"; throw new ArgumentException(err); } int queueId = QueueCounter; if (configQueue.bufferLimit == 0) { queues[queueId] = new BlockingCollection <object>(); } else { queues[queueId] = new BlockingCollection <object>(configQueue.bufferLimit); } queueNameToId.Add(configQueue.name, queueId); QueueCounter++; } // Register connections if (Config.connections == null) { Config.connections = new List <FCFConnection>(); } foreach (var configConnection in Config.connections) { string fromName = configConnection.from; string toName = configConnection.to; int fromElId, toElId; TopologyElementType fromEl = GetTopologyTypeByName(fromName, out fromElId); TopologyElementType toEl = GetTopologyTypeByName(toName, out toElId); if (fromEl == TopologyElementType.None && toEl == TopologyElementType.None) { string err = "Connection from and to elements do not exist: '" + fromName + "' -> '" + toName + "'"; throw new Exception(err); } // node to node, node to queue and queue to node are supported // queue to queue is not supported if (fromEl == TopologyElementType.Queue && toEl == TopologyElementType.Queue) { string err = "Can't connect a queue to a queue: '" + fromName + "' -> '" + toName + "'"; throw new Exception(err); } if (fromEl == TopologyElementType.Node && toEl == TopologyElementType.Queue) { var node = nodes[fromElId]; var queue = queues[toElId]; if (node.Output != null) { string err = "Can't set two output elements for same node: '" + fromName + "' -> '" + toName + "'"; throw new Exception(); } node.Output = queue; node.IsConnected = true; //queueIsToEl[toElId] = true; } if (fromEl == TopologyElementType.Queue && toEl == TopologyElementType.Node) { var node = nodes[toElId]; var queue = queues[fromElId]; if (node.Input != null) { string err = "Can't set two input elements for the same node: '" + fromName + "' -> '" + toName + "'"; throw new Exception(err); } node.Input = queue; node.IsConnected = true; //queueIsFromEl[fromElId] = true; } if (fromEl == TopologyElementType.Node && toEl == TopologyElementType.Node) { var node1 = nodes[fromElId]; node1.IsConnected = true; var node2 = nodes[toElId]; node2.IsConnected = true; if (!IsNodesLongRunning) { node1.NextNode = node2; } } } // a single node may not be connected if (nodes.Length == 1) { nodes[0].IsConnected = true; } // iterate over all tree and check if there are any unconnected nodes foreach (var node in nodes) { if (!node.IsConnected) { string err = "Node is not connected to topology tree: '" + node.Name + "'"; throw new Exception(err); } } /* * * // queues CAN be an edge * * if (queues != null) * { * // check a queue is not an edge * for (var i = 0; i < queues.Length; i++) * { * if (!queueIsFromEl[i] || !queueIsToEl[i]) * { * string err = "A queue cannot be an edge, but must connect a node as input and another node as output"; * throw new Exception(err); * } * } * } */ // several independent topologies can coexist in a single foreman // dispose of helpers //queueIsFromEl = null; //queueIsToEl = null; nodeNameToId = null; IsLoaded = true; }