示例#1
0
        /*
         * 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);
        }
示例#2
0
        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);
        }
示例#3
0
        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;
        }