/// <summary> /// Compiles all decision nodes code and loops code in the given experiment /// </summary> /// <param name="experiment">The experiment.</param> /// <param name="availableInputMappingsPerNode">The available input mappings per node.</param> /// <param name="workspaceTypesDirectories">The workspace types directories.</param> /// <param name="loggerNameRoot">The logger name root.</param> /// <returns> /// true if there were no errors, otherwise false /// </returns> public static bool CompileAllDecisionNodes(IExperiment experiment, InputMappings availableInputMappingsPerNode, List<string> workspaceTypesDirectories, LoggerNameRoot loggerNameRoot) { bool noErrors = true; foreach (ExperimentNode node in experiment.Vertices) { IDecision decisionMetadata = node.Data.Metadata as IDecision; if (decisionMetadata != null) { try { //build successor nodes label id lookup Dictionary<string, string> successorNodeLabelIdLookup = PrepareSuccessorNodesLabelIdLookup(node, experiment); Dictionary<string, string> predeccessorsOutputsNameTypeLookup = PreparePredeccessorsOutputsNameTypeLookup(node, availableInputMappingsPerNode); node.ClearError(); BuildSourceAndCompileDecisionModule(decisionMetadata, successorNodeLabelIdLookup, predeccessorsOutputsNameTypeLookup, workspaceTypesDirectories, loggerNameRoot); } catch (ArgumentException ex) { noErrors = false; node.SetError(ex.Message); } } } return noErrors; }
/// <summary> /// Creates the Runnable node with a specific id based on the given metadata. /// Uses Composite Component Metadata config values to override Components config values in subgraph. /// </summary> /// <param name="id">The id of the node.</param> /// <param name="metadata">The component metadata.</param> /// <param name="loggerNameRoot">The logger name root - needed so that the logs are specific per experiment and experiment window.</param> /// <param name="library">The library of components.</param> /// <param name="componentsAppDomain">The components app domain is the app domain which components assemblies are going to be loaded into.</param> /// <param name="terminateExperimentExecutionResetEvent">The event that allows signalling termination of the experiment; /// Needed for the composite components sublevel experiments, so that they hold the referance to the same termination event as top level experiment</param> /// <returns> /// Created node /// </returns> public override RunnableNode CreateNode(String id, Metadata metadata, LoggerNameRoot loggerNameRoot, ComponentsLibrary library, AppDomain componentsAppDomain, System.Threading.ManualResetEvent terminateExperimentExecutionResetEvent) { RunnableNode retNode; ComponentMetadata originalComponentMetadata = metadata as ComponentMetadata; CompositeComponentMetadata compositeComponentMetadata = metadata as CompositeComponentMetadata; if (originalComponentMetadata != null) { ComponentMetadata overrideComponentMetadata = (ComponentMetadata)originalComponentMetadata.Clone(); OverrideConfigValues(id, overrideComponentMetadata); retNode = base.CreateNode(id, overrideComponentMetadata, loggerNameRoot, library, componentsAppDomain, terminateExperimentExecutionResetEvent); } else if (compositeComponentMetadata != null) { OverrideConfigValues(id, compositeComponentMetadata); retNode = base.CreateCompositeComponentNode(id, compositeComponentMetadata, loggerNameRoot, library, componentsAppDomain, terminateExperimentExecutionResetEvent); } else { retNode = base.CreateNode(id, metadata, loggerNameRoot, library, componentsAppDomain, terminateExperimentExecutionResetEvent); } return retNode; }
/// <summary> /// Validates the entire experiment. /// It validates the structure of the experimental graph, /// validates all inputs and outputs, /// checks if all components are in the component library. /// </summary> /// <param name="experiment">The experiment.</param> /// <param name="vertices">The vertices, that has been parsed from the start node. Nodes that are not connected to the start are being skipped.</param> /// <param name="edges">The edges, that has been parsed from the start node.</param> /// <returns> /// true if there is no errors, false, if errors has been detected /// </returns> public static bool ValidateExperiment(IExperiment experiment, out List<ExperimentNode> vertices, out List<ExperimentNodeConnection> edges, List<string> workspaceTypesDirectories, bool validateInputMapping, LoggerNameRoot loggerNameRoot) { bool noErrors = GraphValidator.Validate(experiment, out vertices, out edges); if (noErrors) { var availableInputMappingsPerNode = new TraceLab.Core.Utilities.InputMappings(experiment); if (validateInputMapping) { noErrors = InputMappingValidator.Validate(experiment, availableInputMappingsPerNode); } if (noErrors) { //recompile all decisions noErrors = TraceLab.Core.Decisions.DecisionCompilationRunner.CompileAllDecisionNodes(experiment, availableInputMappingsPerNode, workspaceTypesDirectories, loggerNameRoot); } } if (noErrors) { noErrors = ValidComponents(vertices); } return noErrors; }
/// <summary> /// Creates the logger for the given metadata and node id /// </summary> /// <param name="loggerNameRoot">The logger name root.</param> /// <param name="nodeId">The node id.</param> /// <param name="loggableMetadata">The metadata.</param> /// <returns></returns> internal static ComponentLogger CreateLogger(LoggerNameRoot loggerNameRoot, string nodeId, ILoggable loggableMetadata) { string loggerName = GetLoggerSourceInfo(nodeId, loggableMetadata, loggerNameRoot); CreateLoggingRules(loggerName, loggableMetadata.LogLevels); if (string.IsNullOrEmpty(loggerName)) loggerName = Guid.NewGuid().ToString(); return new ComponentLoggerImplementation(loggerName); }
/// <summary> /// Creates the Runnable node with a specific id based on the given metadata. /// </summary> /// <param name="nodeId">The node id.</param> /// <param name="metadata">The component metadata.</param> /// <param name="loggerNameRoot">The logger name root - needed so that the logs are specific per experiment and experiment window.</param> /// <param name="library">The library of components.</param> /// <param name="componentsAppDomain">The components app domain is the app domain which components assemblies are going to be loaded into.</param> /// <param name="terminateExperimentExecutionResetEvent">The event that allows signalling termination of the experiment; /// Needed for the composite components sublevel experiments, so that they hold the referance to the same termination event as top level experiment.</param> /// <returns> /// Created node /// </returns> public virtual RunnableNode CreateNode(String nodeId, Metadata metadata, LoggerNameRoot loggerNameRoot, ComponentsLibrary library, AppDomain componentsAppDomain, System.Threading.ManualResetEvent terminateExperimentExecutionResetEvent) { RunnableNode retNode; ComponentMetadata componentMetadata = metadata as ComponentMetadata; DecisionMetadata decisionMetadata = metadata as DecisionMetadata; StartNodeMetadata startNodeMetadata = metadata as StartNodeMetadata; EndNodeMetadata endNodeMetadata = metadata as EndNodeMetadata; ScopeBaseMetadata scopeMetadata = metadata as ScopeBaseMetadata; LoopScopeMetadata loopMetadata = metadata as LoopScopeMetadata; CompositeComponentMetadata compositeComponentMetadata = metadata as CompositeComponentMetadata; ExitDecisionMetadata exitDecisionMetadata = metadata as ExitDecisionMetadata; if (componentMetadata != null) { TraceLabSDK.ComponentLogger logger = TraceLab.Core.Components.LoggerFactory.CreateLogger(loggerNameRoot, nodeId, componentMetadata); IComponent component = library.LoadComponent(componentMetadata, Workspace, logger, componentsAppDomain); retNode = new RunnableComponentNode(nodeId, componentMetadata.Label, component, logger, library, componentMetadata.WaitsForAllPredecessors); } else if (decisionMetadata != null) { IDecisionModule decisionModule = DecisionModuleFactory.LoadDecisionModule(decisionMetadata, Workspace, componentsAppDomain); retNode = new RunnableDecisionNode(nodeId, decisionMetadata.Label, decisionModule, library, decisionMetadata.WaitsForAllPredecessors); } else if (startNodeMetadata != null) { retNode = new RunnableStartNode(nodeId); } else if (endNodeMetadata != null) { retNode = new RunnableEndNode(nodeId, endNodeMetadata.WaitsForAllPredecessors); } else if (loopMetadata != null) { retNode = CreateLoopNode(nodeId, loopMetadata, loggerNameRoot, library, componentsAppDomain, terminateExperimentExecutionResetEvent); } else if (scopeMetadata != null) { retNode = CreateScopeCompositeComponentNode(nodeId, scopeMetadata, loggerNameRoot, library, componentsAppDomain, terminateExperimentExecutionResetEvent); } else if (compositeComponentMetadata != null) { retNode = CreateCompositeComponentNode(nodeId, compositeComponentMetadata, loggerNameRoot, library, componentsAppDomain, terminateExperimentExecutionResetEvent); } else if (exitDecisionMetadata != null) { retNode = new RunnablePrimitiveNode(nodeId, exitDecisionMetadata.WaitsForAllPredecessors); } else { throw new Exceptions.InconsistentTemplateException("Could not identify node type."); } return retNode; }
/// <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> /// Creates the logger for the given metadata and node id /// </summary> /// <param name="loggerNameRoot">The logger name root.</param> /// <param name="nodeId">The node id.</param> /// <param name="loggableMetadata">The metadata.</param> /// <returns></returns> internal static ComponentLogger CreateLogger(LoggerNameRoot loggerNameRoot, string nodeId, ILoggable loggableMetadata) { string loggerName = GetLoggerSourceInfo(nodeId, loggableMetadata, loggerNameRoot); CreateLoggingRules(loggerName, loggableMetadata.LogLevels); if (string.IsNullOrEmpty(loggerName)) { loggerName = Guid.NewGuid().ToString(); } return(new ComponentLoggerImplementation(loggerName)); }
/// <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="loggerNameRoot">The logger name root - needed so that the logs are specific per experiment and experiment window.</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> /// <param name="componentsAppDomain">The components app domain is the app domain which components assemblies are going to be loaded into.</param> /// <param name="terminateExperimentExecutionResetEvent">The event that allows signalling termination of the experiment</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, LoggerNameRoot loggerNameRoot, IRunnableNodeFactory nodesFactory, Components.ComponentsLibrary library, List<string> workspaceTypeDirectories, AppDomain componentsAppDomain, System.Threading.ManualResetEvent terminateExperimentExecutionResetEvent, bool validateInputMapping) { RunnableExperimentBase runnableExperiment = new RunnableExperiment(nodesFactory, library, componentsAppDomain, terminateExperimentExecutionResetEvent); List<ExperimentNode> vertices; List<ExperimentNodeConnection> edges; bool noErrors = ExperimentValidator.ValidateExperiment(experiment, out vertices, out edges, workspaceTypeDirectories, validateInputMapping, loggerNameRoot); if (noErrors) { foreach (ExperimentNode node in vertices) { try { runnableExperiment.AddNode(node.ID, node.Data.Metadata, loggerNameRoot); } catch (TraceLab.Core.Exceptions.IncorrectSubTemplateException ex) { runnableExperiment.Clear(); noErrors = false; NLog.LogManager.GetCurrentClassLogger().Error(ex.Message); node.SetError(ex.Message); break; } catch (Exception ex) { runnableExperiment.Clear(); noErrors = false; string msg = "Unable to initialize component: " + ex.Message; NLog.LogManager.GetCurrentClassLogger().Error(msg, ex); node.SetError(msg); break; } } } if (noErrors) { foreach (ExperimentNodeConnection edge in edges) { runnableExperiment.AddDirectedEdge(edge.Source.ID, edge.Target.ID); } } return runnableExperiment; }
/// <summary> /// Gets the name of the logger constructed from several parts. /// </summary> /// <param name="nodeId">The node id.</param> /// <param name="loggerNameRoot">The logger name root.</param> /// <param name="componentName">Name of the component.</param> /// <param name="sourceAssembly">The source assembly.</param> /// <param name="componentLabel">The component label.</param> /// <returns></returns> private static string GetLoggerSourceInfo(string nodeId, LoggerNameRoot loggerNameRoot, string componentName, string sourceAssembly, string componentLabel) { string loggerName; if (String.IsNullOrEmpty(loggerNameRoot.UserFriendlyRoot)) { //skip the user friendly root loggerName = String.Format("{0}:{1}::Classname:{2}::SourceAssembly:{3}::Label:{4}", loggerNameRoot.ExperimentPathRoot, nodeId, componentName, sourceAssembly, componentLabel); } else { //otherwise show user friendly root loggerName = String.Format("{0}:{1}::Classname:{2}::SourceAssembly:{3}::Label:{4} : {5}", loggerNameRoot.ExperimentPathRoot, nodeId, componentName, sourceAssembly, loggerNameRoot.UserFriendlyRoot, componentLabel); } return(loggerName); }
/// <summary> /// Compiles the code of the single decision node or loop scope node. It handles DecisionNode and LoopScopeNode slightly differently. /// Method. /// </summary> /// <param name="node">The node.</param> /// <param name="experiment">The experiment.</param> /// <param name="workspaceTypesDirectories">The workspace types directories.</param> /// <param name="loggerNameRoot">The logger name root.</param> public static void CompileDecision(ExperimentNode node, IExperiment experiment, List<string> workspaceTypesDirectories, LoggerNameRoot loggerNameRoot) { ExperimentDecisionNode decisionNode = node as ExperimentDecisionNode; if (decisionNode != null) { Dictionary<string, string> successorNodeLabelIdLookup = PrepareSuccessorNodesLabelIdLookup(node, experiment); CompileDecisionInternal(decisionNode, experiment, workspaceTypesDirectories, loggerNameRoot, successorNodeLabelIdLookup); } else { LoopScopeNode loopScopeNode = node as LoopScopeNode; if (loopScopeNode != null) { //loop scope does not need successor nodes lookups, so pass in empty dictionary Dictionary<string, string> successorNodeLabelIdLookup = new Dictionary<string, string>(); CompileDecisionInternal(loopScopeNode, experiment, workspaceTypesDirectories, loggerNameRoot, successorNodeLabelIdLookup); } } }
/// <summary> /// Gets the name of the logger constructed from several parts. /// </summary> /// <param name="nodeId">The node id.</param> /// <param name="loggerNameRoot">The logger name root.</param> /// <param name="componentName">Name of the component.</param> /// <param name="sourceAssembly">The source assembly.</param> /// <param name="componentLabel">The component label.</param> /// <returns></returns> private static string GetLoggerSourceInfo(string nodeId, LoggerNameRoot loggerNameRoot, string componentName, string sourceAssembly, string componentLabel) { string loggerName; if (String.IsNullOrEmpty(loggerNameRoot.UserFriendlyRoot)) { //skip the user friendly root loggerName = String.Format("{0}:{1}::Classname:{2}::SourceAssembly:{3}::Label:{4}", loggerNameRoot.ExperimentPathRoot, nodeId, componentName, sourceAssembly, componentLabel); } else { //otherwise show user friendly root loggerName = String.Format("{0}:{1}::Classname:{2}::SourceAssembly:{3}::Label:{4} : {5}", loggerNameRoot.ExperimentPathRoot, nodeId, componentName, sourceAssembly, loggerNameRoot.UserFriendlyRoot, componentLabel); } return loggerName; }
/// <summary> /// Gets the logger source info. /// </summary> /// <param name="nodeId">The node id.</param> /// <param name="loggableMetadata">The loggable metadata.</param> /// <param name="loggerNameRoot">The logger name root.</param> /// <returns></returns> private static string GetLoggerSourceInfo(string nodeId, ILoggable loggableMetadata, LoggerNameRoot loggerNameRoot) { return GetLoggerSourceInfo(nodeId, loggerNameRoot, loggableMetadata.Classname, loggableMetadata.SourceAssembly, loggableMetadata.Label); }
/// <summary> /// Handles the event of Check Code Button Click. /// It compiles decision code. /// </summary> /// <param name="sender">Sender.</param> /// <param name="e">E.</param> protected void CheckCode (object sender, EventArgs e) { List<string> workspaceTypeDirectories = m_applicationContext.Application.WorkspaceViewModel.WorkspaceTypeDirectories; Experiment experiment = m_applicationContext.Application.Experiment; LoggerNameRoot loggerNameRoot = new LoggerNameRoot(experiment.ExperimentInfo.Id); //compile decision - the result is set in metadata Compilation Status, and eventual message in Error TraceLab.Core.Decisions.DecisionCompilationRunner.CompileDecision(m_decisionControl.ExperimentNode, experiment, workspaceTypeDirectories, loggerNameRoot); //retrieve compilation status from metadata if(m_metadata.CompilationStatus == CompilationStatus.Successful) { this.errorTextView.ShowInfoMessage("Compilation successful!"); } //otherwise error displays on ErrorChanged event - see HandleErrorChanged method }
/// <summary> /// Adds the node. /// </summary> /// <param name="id">The id.</param> /// <param name="metadata">The metadata.</param> public override void AddNode(String id, Metadata metadata, LoggerNameRoot loggerNameRoot) { // adds a node to the graph RunnableNode node = m_nodesFactory.CreateNode(id, metadata, loggerNameRoot, Library, ComponentsAppDomain, TerminateExperimentExecutionResetEvent); if (node is RunnableStartNode) { //allow set only once if (m_startNode != null) { throw new TraceLab.Core.Exceptions.InconsistentTemplateException("Template cannot have two start nodes defined."); } m_startNode = node; } if (node is RunnableEndNode) { //allow set only once if (m_endNode != null) { throw new TraceLab.Core.Exceptions.InconsistentTemplateException("Template cannot have two end nodes defined."); } m_endNode = node; } m_nodes.Add(node); }
/// <summary> /// Compiles the decision module func. /// </summary> /// <param name="param">The param.</param> private void CompileDecisionModuleFunc(object param) { var args = param as List<object>; if (args != null && args.Count == 2) { //validate args var node = args[0] as ExperimentNode; var appVM = args[1] as ApplicationViewModelWrapper; if (node != null && appVM != null) { List<string> workspaceTypeDirectories = appVM.WorkspaceViewModel.WorkspaceTypeDirectories; string topExperimentId = appVM.ExperimentViewModel.TopLevel.ExperimentInfo.Id; LoggerNameRoot loggerNameRoot = new LoggerNameRoot(topExperimentId); TraceLab.Core.Decisions.DecisionCompilationRunner.CompileDecision(node, m_experiment, workspaceTypeDirectories, loggerNameRoot); } } }
/// <summary> /// Creates the scope composite component node. It actually returns the composite component, but with different nested workspace wrapper. /// </summary> /// <param name="id">The id.</param> /// <param name="loopScopeMetadata">The scope metadata.</param> /// <param name="loggerNameRoot">The logger name root.</param> /// <param name="library">The library.</param> /// <param name="componentsAppDomain">The components app domain.</param> /// <param name="terminateExperimentExecutionResetEvent">The terminate experiment execution reset event.</param> /// <returns></returns> protected RunnableNode CreateLoopNode(string id, LoopScopeMetadata loopScopeMetadata, LoggerNameRoot loggerNameRoot, ComponentsLibrary library, AppDomain componentsAppDomain, System.Threading.ManualResetEvent terminateExperimentExecutionResetEvent) { ScopeNestedWorkspaceWrapper workspaceWrapper = WorkspaceWrapperFactory.CreateCompositeComponentWorkspaceWrapper(loopScopeMetadata, Workspace, id, componentsAppDomain); //scope can standard runnable factory, unlike the composite component IRunnableNodeFactory nodesFactory = new RunnableNodeFactory(workspaceWrapper); RunnableExperimentBase subExperiment = ConstructSubExperiment(loopScopeMetadata, loggerNameRoot, library, componentsAppDomain, terminateExperimentExecutionResetEvent, nodesFactory); ILoopDecisionModule decisionModule = DecisionModuleFactory.LoadDecisionModule(loopScopeMetadata, Workspace, componentsAppDomain); return new RunnableLoopNode(id, decisionModule, loopScopeMetadata, subExperiment, workspaceWrapper, library, loopScopeMetadata.WaitsForAllPredecessors); }
public RunnableNode CreateNode(string id, Metadata metadata, LoggerNameRoot loggerNameRoot, TraceLab.Core.Components.ComponentsLibrary library, AppDomain componentsAppDomain, System.Threading.ManualResetEvent terminateExperimentExecutionResetEvent) { return CreateNode(id, metadata, terminateExperimentExecutionResetEvent); }
/// <summary> /// Gets the logger source info. /// </summary> /// <param name="nodeId">The node id.</param> /// <param name="loggableMetadata">The loggable metadata.</param> /// <param name="loggerNameRoot">The logger name root.</param> /// <returns></returns> private static string GetLoggerSourceInfo(string nodeId, ILoggable loggableMetadata, LoggerNameRoot loggerNameRoot) { return(GetLoggerSourceInfo(nodeId, loggerNameRoot, loggableMetadata.Classname, loggableMetadata.SourceAssembly, loggableMetadata.Label)); }
/// <summary> /// Adds the node. /// </summary> /// <param name="id">The id.</param> /// <param name="metadata">The metadata.</param> /// <param name="loggerNameRoot">The logger name root.</param> public abstract void AddNode(String id, Metadata metadata, LoggerNameRoot loggerNameRoot);
/// <summary> /// Validates the entire experiment. /// It validates the structure of the experimental graph, /// validates all inputs and outputs, /// checks if all components are in the component library. /// </summary> /// <param name="experiment">The experiment.</param> /// <returns>true if there is no errors, false, if errors has been detected</returns> public static bool ValidateExperiment(IExperiment experiment, List<string> workspaceTypesDirectories, LoggerNameRoot loggerNameRoot) { List<ExperimentNode> vertices; List<ExperimentNodeConnection> edges; return ValidateExperiment(experiment, out vertices, out edges, workspaceTypesDirectories, true, loggerNameRoot); }
/// <summary> /// Creates the composite component node. /// </summary> /// <param name="id">The id.</param> /// <param name="compositeComponentMetadata">The composite component metadata.</param> /// <param name="loggerNameRoot">The logger name root - needed so that the logs are specific per experiment and experiment window.</param> /// <param name="library">The library of components.</param> /// <param name="componentsAppDomain">The components app domain is the app domain which components assemblies are going to be loaded into.</param> /// <param name="terminateExperimentExecutionResetEvent">The event that allows signalling termination of the experiment; The sublevel experiments hold the referance to the same termination event as top level experiment.</param> /// <returns> /// Created composite component node /// </returns> protected RunnableNode CreateCompositeComponentNode(string id, CompositeComponentMetadata compositeComponentMetadata, LoggerNameRoot loggerNameRoot, ComponentsLibrary library, AppDomain componentsAppDomain, System.Threading.ManualResetEvent terminateExperimentExecutionResetEvent) { NestedWorkspaceWrapper workspaceWrapper = WorkspaceWrapperFactory.CreateCompositeComponentWorkspaceWrapper(compositeComponentMetadata, Workspace, id, componentsAppDomain); NodesFactoryOfSubGraph nodesFactoryOfSubGraph = new NodesFactoryOfSubGraph(compositeComponentMetadata, workspaceWrapper); RunnableExperimentBase subExperiment = ConstructSubExperiment(compositeComponentMetadata, loggerNameRoot, library, componentsAppDomain, terminateExperimentExecutionResetEvent, nodesFactoryOfSubGraph); return new RunnableCompositeComponentNode(id, compositeComponentMetadata, subExperiment, workspaceWrapper, library, compositeComponentMetadata.WaitsForAllPredecessors); }
/// <summary> /// Compiles the decision. /// </summary> /// <param name="node">The node.</param> /// <param name="experiment">The experiment.</param> /// <param name="workspaceTypesDirectories">The workspace types directories.</param> /// <param name="loggerNameRoot">The logger name root.</param> private static void CompileDecisionInternal(ExperimentNode node, IExperiment experiment, List<string> workspaceTypesDirectories, LoggerNameRoot loggerNameRoot, Dictionary<string, string> successorNodeLabelIdLookup) { InputMappings availableInputMappingsPerNode = new InputMappings(experiment); Dictionary<string, string> predeccessorsOutputsNameTypeLookup = PreparePredeccessorsOutputsNameTypeLookup(node, availableInputMappingsPerNode); IDecision decisionMetadata = (IDecision)node.Data.Metadata; try { if (decisionMetadata != null) { node.ClearError(); BuildSourceAndCompileDecisionModule(decisionMetadata, successorNodeLabelIdLookup, predeccessorsOutputsNameTypeLookup, workspaceTypesDirectories, loggerNameRoot); decisionMetadata.CompilationStatus = TraceLab.Core.Components.CompilationStatus.Successful; } } catch (ArgumentException ex) { decisionMetadata.CompilationStatus = TraceLab.Core.Components.CompilationStatus.Failed; node.SetError(ex.Message); } }
/// <summary> /// Constructs the sub experiment. /// </summary> /// <param name="compositeComponentMetadata">The composite component metadata.</param> /// <param name="loggerNameRoot">The logger name root.</param> /// <param name="library">The library.</param> /// <param name="componentsAppDomain">The components app domain.</param> /// <param name="terminateExperimentExecutionResetEvent">The terminate experiment execution reset event - must be the same as top level experiment termination event.</param> /// <param name="nodesFactoryOfSubGraph">The nodes factory of sub graph.</param> /// <returns></returns> private RunnableExperimentBase ConstructSubExperiment(CompositeComponentBaseMetadata compositeComponentMetadata, LoggerNameRoot loggerNameRoot, ComponentsLibrary library, AppDomain componentsAppDomain, System.Threading.ManualResetEvent terminateExperimentExecutionResetEvent, IRunnableNodeFactory nodesFactoryOfSubGraph) { //add to experiment id the owner node id to make it unique LoggerNameRoot compositeComponentNodeLoggerNameRoot = loggerNameRoot.CreateLoggerNameRootForCompositeNode(compositeComponentMetadata); RunnableExperimentBase subExperiment = GraphAdapter.Adapt(compositeComponentMetadata.ComponentGraph, compositeComponentNodeLoggerNameRoot, nodesFactoryOfSubGraph, library, Workspace.TypeDirectories, componentsAppDomain, terminateExperimentExecutionResetEvent, false); if (subExperiment.IsEmpty) { throw new TraceLab.Core.Exceptions.IncorrectSubTemplateException("Unable to execute subexperiment due to errors."); } return subExperiment; }
/// <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 }