/// <summary> /// Adapts the specified experiment into runnable experiment. /// Adapt method validates given experiment and builds runnable experiment which is going to be executed by the experiment runner. /// During adapation the experiment is validated. /// In case of detected error in the experiment, this method returns empty RunnableExperimentBase with no nodes and no edges. /// There are several errors that can be detected. /// There are nodes connected to start, but not to graph end. /// Loops without decisions nodes. /// Input mappings are incorrect. /// Failed component load or instantiation, especially in case of incorrect configuration values. /// </summary> /// <param name="experiment">The experiment which is going to be adapted into RunnableExperiment..</param> /// <param name="nodesFactory">The nodes factory, by which all nodes in runnable experiment are created..</param> /// <param name="library">The library of components.</param> /// <param name="workspaceTypeDirectories">The workspace type directories.</param> /// <returns> /// Runnable experiment that experiment is going to execute, pruned from nodes that are not connected to main flow beginning at Start node. /// In case of detected error in the experiment, this method returns empty RunnableExperimentBase with no nodes and no edges. /// </returns> public static RunnableExperimentBase Adapt(IExperiment experiment, IRunnableNodeFactory nodesFactory, Components.ComponentsLibrary library, List <string> workspaceTypeDirectories) { LoggerNameRoot loggerNameRoot = new LoggerNameRoot(experiment.ExperimentInfo.Id); // Create the new domain for the runnable experiment with whatever current security evidence we're running with. // The components app domain is the app domain which components assemblies are going to be loaded into. var helper = new TraceLab.Core.Components.LibraryHelper(workspaceTypeDirectories); AppDomain componentsAppDomain = helper.CreateDomain(experiment.ExperimentInfo.Id); return(Adapt(experiment, loggerNameRoot, nodesFactory, library, workspaceTypeDirectories, componentsAppDomain, new System.Threading.ManualResetEvent(false), true)); }
/// <summary> /// Adapts the specified experiment into runnable experiment. /// Adapt method validates given experiment and builds runnable experiment which is going to be executed by the experiment runner. /// During adapation the experiment is validated. /// In case of detected error in the experiment, this method returns empty RunnableExperimentBase with no nodes and no edges. /// There are several errors that can be detected. /// There are nodes connected to start, but not to graph end. /// Loops without decisions nodes. /// Input mappings are incorrect. /// Failed component load or instantiation, especially in case of incorrect configuration values. /// </summary> /// <param name="experiment">The experiment which is going to be adapted into RunnableExperiment..</param> /// <param name="nodesFactory">The nodes factory, by which all nodes in runnable experiment are created..</param> /// <param name="library">The library of components.</param> /// <param name="workspaceTypeDirectories">The workspace type directories.</param> /// <returns> /// Runnable experiment that experiment is going to execute, pruned from nodes that are not connected to main flow beginning at Start node. /// In case of detected error in the experiment, this method returns empty RunnableExperimentBase with no nodes and no edges. /// </returns> public static RunnableExperimentBase Adapt(IExperiment experiment, IRunnableNodeFactory nodesFactory, Components.ComponentsLibrary library, List<string> workspaceTypeDirectories) { LoggerNameRoot loggerNameRoot = new LoggerNameRoot(experiment.ExperimentInfo.Id); // Create the new domain for the runnable experiment with whatever current security evidence we're running with. // The components app domain is the app domain which components assemblies are going to be loaded into. var helper = new TraceLab.Core.Components.LibraryHelper(workspaceTypeDirectories); AppDomain componentsAppDomain = helper.CreateDomain(experiment.ExperimentInfo.Id); return Adapt(experiment, loggerNameRoot, nodesFactory, library, workspaceTypeDirectories, componentsAppDomain, new System.Threading.ManualResetEvent(false), true); }
/// <summary> /// Scans the specified directories for components not already present in cache. /// </summary> /// <param name="directories">The directories.</param> /// <param name="workspaceTypeDirectories">The workspace type directories.</param> /// <param name="cachedFiles">Components already loaded in the cache.</param> /// <param name="results">.</param> /// <returns> /// True or False depending on the success of the scanning operation. /// </returns> public static bool Scan(IEnumerable<string> directories, IEnumerable<string> workspaceTypeDirectories, ISet<string> cachedFiles, ComponentScanResults results) { bool success = true; AppDomain newDomain = null; try { var libraryHelper = new LibraryHelper(workspaceTypeDirectories); newDomain = libraryHelper.CreateDomain("ComponentScanner", false); newDomain.Load(Assembly.GetExecutingAssembly().GetName()); // Preload the workspace types so that the component scanner won't barf when a component references a workspace type. libraryHelper.PreloadWorkspaceTypes(newDomain); ComponentScanner scanner = (ComponentScanner)newDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(ComponentScanner).FullName, false, BindingFlags.Instance | BindingFlags.NonPublic, null, null, null, null); if (!RuntimeInfo.IsRunInMono) { scanner.Scan(directories, cachedFiles); } else { scanner.Scan(directories, new List<string>(cachedFiles)); } results.NewFilesLoaded = new List<FileDescriptor>(scanner.NewFilesLoaded); results.RequestedFiles = new List<string>(scanner.FilesToGetFromCache); results.Errors = new List<string>(scanner.Errors); } catch (Exception e) { success = false; results.NewFilesLoaded = new List<FileDescriptor>(); results.RequestedFiles = new List<string>(); results.OldGuidToNewGuidMap = new Dictionary<string, string>(); results.Errors = results.Errors ?? new List<string>(); results.Errors.Add(e.Message); } finally { if (newDomain != null) { #if !MONO_DEV //appdomain unload crashes mono.exe process when running directly from //Mono Develop, possibly because attached debugger. When run normally works fine. //use MONO_DEV compiler symbol when developing AppDomain.Unload(newDomain); #endif } } return success; }
/// <summary> /// Builds the source of decision module and compile decision module into the assembly /// </summary> /// <param name="metadata">The metadata.</param> /// <param name="successorNodeLabelIdLookup">The successor node label id lookup.</param> /// <param name="predeccessorsOutputsNameTypeLookup">The predeccessors outputs name type lookup.</param> /// <param name="workspaceTypesDirectories">The workspace types directories.</param> /// <param name="loggerNameRoot">The logger name root.</param> private static void BuildSourceAndCompileDecisionModule(IDecision metadata, Dictionary<string, string> successorNodeLabelIdLookup, Dictionary<string, string> predeccessorsOutputsNameTypeLookup, List<string> workspaceTypesDirectories, LoggerNameRoot loggerNameRoot) { metadata.FireRequestLatestCode(); //create local componentlogger (ComponentLoggerImplementation implements MarshalByRefObject, thanks to which it can pass logs between appdomains TraceLabSDK.ComponentLogger logger = LoggerFactory.CreateLogger(loggerNameRoot, metadata.UniqueDecisionID, metadata); //construct the final code, and collect types assemblies locations to be referenced by the compilator HashSet<string> assembliesReferenceLocations; string finalDecisionModuleSourceCode = DecisionCodeBuilder.BuildCodeSource(metadata, workspaceTypesDirectories, successorNodeLabelIdLookup, predeccessorsOutputsNameTypeLookup, logger, out assembliesReferenceLocations); // Create the new domain with whatever current security evidence we're running with using the library helper LibraryHelper helper = new LibraryHelper(workspaceTypesDirectories); AppDomain newDomain = helper.CreateDomain("DecisionModuleCompilation"); newDomain.Load(Assembly.GetExecutingAssembly().GetName()); helper.PreloadWorkspaceTypes(newDomain); //// Load our output assembly into the other domain. DecisionModuleCompilator compiler = (DecisionModuleCompilator)newDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(DecisionModuleCompilator).FullName, false, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.CreateInstance | BindingFlags.Instance, null, new object[] { }, System.Globalization.CultureInfo.CurrentCulture, new object[] { }); compiler.CompileDecisionModule(finalDecisionModuleSourceCode, metadata.SourceAssembly, assembliesReferenceLocations); #if !MONO_DEV //when developing on mono in MonoDevelop application crashes when unloading appdomain. //it only happens from within of MonoDevelop with attached debugger. Running normally, works fine. AppDomain.Unload(newDomain); #endif }