Пример #1
0
        /// <summary>
        /// Register an error that occurred while working with this
        /// instance.
        /// </summary>
        /// <param name="ex">
        /// The exception that occurred.
        /// </param>
        /// <param name="flowElement">
        /// The flow element that the exception occurred in.
        /// </param>
        /// <param name="shouldThrow">
        /// Set whether the pipeline should throw the exception.
        /// </param>
        /// <param name="shouldLog">
        /// Set whether the pipeline should log the exception as an error.
        /// </param>
        public void AddError(Exception ex, IFlowElement flowElement, bool shouldThrow, bool shouldLog)
        {
            if (_errors == null)
            {
                _errors = new List <IFlowError>();
            }
            if (_errorsLock == null)
            {
                _errorsLock = new object();
            }
            var error = new FlowError(ex, flowElement, shouldThrow);

            lock (_errorsLock)
            {
                _errors.Add(error);
            }

            if (_logger != null && _logger.IsEnabled(LogLevel.Error) && shouldLog)
            {
                string logMessage = "Error occurred during processing";
                if (flowElement != null)
                {
                    logMessage = logMessage + $" of {flowElement.GetType().Name}";
                }
                _logger.LogError(ex, logMessage);
            }
        }
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="pipelinesAccessor">
 /// A function that returns the list of pipelines associated
 /// with the parent engine.
 /// </param>
 /// <param name="currentElement">
 /// The <see cref="IFlowElement"/> this instance of
 /// RequestEngineAccessor was created by.
 /// </param>
 public RequestEngineAccessor(
     Func <IReadOnlyList <IPipeline> > pipelinesAccessor,
     IFlowElement currentElement)
 {
     _currentElement    = currentElement;
     _pipelinesAccessor = pipelinesAccessor;
 }
Пример #3
0
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="element">
        /// The <see cref="IFlowElement"/> that this property is associated
        /// with.
        /// </param>
        /// <param name="name">
        /// The name of the property. Must match the string key used to
        /// store the property value in the <see cref="IElementData"/> instance.
        /// </param>
        /// <param name="type">
        /// The type of the property values.
        /// </param>
        /// <param name="category">
        /// The category the property belongs to.
        /// </param>
        /// <param name="available">
        /// True if the property is available.
        /// </param>
        /// <param name="itemProperties">
        /// Where this meta-data instance relates to a list of complex objects,
        /// this parameter can contain a list of the property meta-data
        /// for items in that list.
        /// </param>
        /// <param name="delayExecution">
        /// Only relevant if <see cref="Type"/> is <see cref="JavaScript"/>.
        /// Defaults to false.
        /// If set to true then the JavaScript in this property will
        /// not be executed automatically on the client device.
        /// </param>
        /// <param name="evidenceProperties">
        /// The names of any <see cref="JavaScript"/> properties that,
        /// when executed, will obtain additional evidence that can help
        /// in determining the value of this property.
        /// Note that these names should include any parts after the
        /// element data key.
        /// I.e. if the complete property name is
        /// 'devices.profiles.screenwidthpixelsjavascript' then the
        /// name in this list must be 'profiles.screenwidthpixelsjavascript'
        /// </param>
        public ElementPropertyMetaData(
            IFlowElement element,
            string name,
            Type type,
            bool available,
            string category = "",
            IReadOnlyList <IElementPropertyMetaData> itemProperties = null,
            bool delayExecution = false,
            IReadOnlyList <string> evidenceProperties = null)
        {
            // WARNING: If you are adding properties to this constructor
            // that need to be exposed through the cloud service then you'll
            // also need to update:
            // - Pipeline.Core.Data.PropertyMetaData
            // - FiftyOne.Pipeline.CloudRequestEngine.FlowElements.CloudRequestEngineBase.LoadProperty()
            Element            = element;
            Name               = name;
            Type               = type;
            Category           = category;
            Available          = available;
            ItemProperties     = itemProperties;
            DelayExecution     = delayExecution;
            EvidenceProperties = evidenceProperties;

            _itemPropertyDictionary = new Lazy <IReadOnlyDictionary <string, IElementPropertyMetaData> >(() =>
            {
                return(ItemProperties?.ToDictionary(p => p.Name, p => p, StringComparer.OrdinalIgnoreCase));
            });
        }
Пример #4
0
        private IFlowElement register <T>(IFlowElement element)
        {
            this.elements.Add(element);
            this.tasks.Add(((ITaskElement)element).MyTask);

            if (this.elements.Count > 1)
            {
                IFlowElement previous = this.elements[this.elements.Count - 2];
                if (!(previous is IDone <T>))
                {
                    this.elements.Remove(this.elements.Last());
                    this.tasks.Remove(this.tasks.Last());
                    Type iDoneType = previous.GetIDoneType();
                    if (iDoneType == typeof(void))
                    {
                        throw new FlowRegisterException();
                    }
                    else
                    {
                        throw new FlowRegisterException(iDoneType);
                    }
                }
                else
                {
                    ((IDone <T>)previous).Done         += ((IRun <T>) this.elements.Last()).Run;
                    ((IFail)this.elements.Last()).Fail += callFailAndAlways;
                }
            }
            return(this.elements.Last());
        }
 /// <summary>
 /// Add the specified <see cref="IFlowElement"/> to the pipeline.
 /// Elements are typically executed sequentially in the order
 /// they are added.
 /// </summary>
 /// <param name="element">
 /// The <see cref="IFlowElement"/> to add
 /// </param>
 /// <returns>
 /// This builder instance.
 /// </returns>
 /// <exception cref="ObjectDisposedException">
 /// Thrown if the element has already been disposed.
 /// </exception>
 /// <exception cref="ArgumentNullException">
 /// Thrown if the supplied element is null.
 /// </exception>
 public T AddFlowElement(IFlowElement element)
 {
     if (element == null)
     {
         throw new ArgumentNullException(nameof(element));
     }
     if (element.IsDisposed)
     {
         throw new ObjectDisposedException(nameof(element));
     }
     FlowElements.Add(element);
     return(this as T);
 }
Пример #6
0
 /// <summary>
 /// Get the <see cref="IElementData"/> instance containing data
 /// populated by the specified element.
 /// </summary>
 /// <typeparam name="T">
 /// The expected type of the data to be returned.
 /// </typeparam>
 /// <typeparam name="TMeta">
 /// The type of meta data that the flow element will supply
 /// about the properties it populates.
 /// </typeparam>
 /// <param name="flowElement">
 /// The <see cref="IFlowElement{T, TMeta}"/> that populated the
 /// desired data.
 /// </param>
 /// <returns>
 /// An instance of type T containing the data.
 /// </returns>
 /// <exception cref="ArgumentNullException">
 /// Thrown if the supplied flow element is null
 /// </exception>
 /// <exception cref="PipelineException">
 /// Thrown if this FlowData instance has not been processed yet.
 /// </exception>
 public T GetFromElement <T, TMeta>(IFlowElement <T, TMeta> flowElement)
     where T : IElementData
     where TMeta : IElementPropertyMetaData
 {
     if (_processed == false)
     {
         throw new PipelineException(Messages.ExceptionFlowDataNotYetProcessed);
     }
     if (flowElement == null)
     {
         throw new ArgumentNullException(nameof(flowElement));
     }
     return(_data.Get(flowElement.ElementDataKeyTyped));
 }
Пример #7
0
 private void registerAdditionalEvents <TResult>(ref IFlowElement element, Action <TResult> onDone, Action <Exception> onFail, Action onAlways)
 {
     if (onDone != null)
     {
         ((IDone <TResult>)element).Done += onDone;
     }
     if (onFail != null)
     {
         ((IFail)element).Fail += onFail;
     }
     if (onAlways != null)
     {
         ((IAlways)element).Always += onAlways;
     }
 }
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="element">
 /// The <see cref="IFlowElement"/> that this property is associated
 /// with.
 /// </param>
 /// <param name="name">
 /// The name of the property. Must match the string key used to
 /// store the property value in the <see cref="IElementData"/> instance.
 /// </param>
 /// <param name="type">
 /// The type of the property values.
 /// </param>
 /// <param name="category">
 /// The category the property belongs to.
 /// </param>
 /// <param name="available">
 /// True if the property is available.
 /// </param>
 /// <param name="itemProperties">
 /// Where this meta-data instance relates to a list of complex objects,
 /// this parameter can contain a list of the property meta-data
 /// for items in that list.
 /// </param>
 public ElementPropertyMetaData(
     IFlowElement element,
     string name,
     Type type,
     bool available,
     string category = "",
     IReadOnlyList <IElementPropertyMetaData> itemProperties = null)
 {
     Element        = element;
     Name           = name;
     Type           = type;
     Category       = category;
     Available      = available;
     ItemProperties = itemProperties;
 }
Пример #9
0
        private static Type getGenericInterfaceType(IFlowElement element, string name)
        {
            Type result = getInterfaceType(element, name);

            if (result == default(Type))
            {
                return(typeof(void));
            }
            else if (!result.IsGenericType)
            {
                return(typeof(void));
            }
            else
            {
                return(result.GetGenericArguments()[0]);
            }
        }
        private void assertFlowElementIs(Type elementClass)
        {
            IBpmnModelInstance modelInstance = ModelExecutionContextExecutionListener.ModelInstance;

            Assert.NotNull(modelInstance);

            IModel model = modelInstance.Model;
            IEnumerable <IModelElementInstance> events = modelInstance.GetModelElementsByType(model.GetType(typeof(IEvent)));

            Assert.AreEqual(3, events.Count());
            IEnumerable <IModelElementInstance> gateways = modelInstance.GetModelElementsByType(model.GetType(typeof(IGateway)));

            Assert.AreEqual(1, gateways.Count());
            IEnumerable <IModelElementInstance> tasks = modelInstance.GetModelElementsByType(model.GetType(typeof(ITask)));

            Assert.AreEqual(1, tasks.Count());

            IFlowElement flowElement = ModelExecutionContextExecutionListener.FlowElement;

            Assert.NotNull(flowElement);
            Assert.True(elementClass.IsAssignableFrom(flowElement.GetType()));
        }
Пример #11
0
        private void MenuSelected(MenuModel menu)
        {
            if (Works.FirstOrDefault(x => x.Menu.Equals(menu)) is null)
            {
                IFlowElement content = null;

                switch (menu.IconType)
                {
                case GeoIcon.FolderOpenOutline: content = new Finder().UseViewModel(new FinderViewModel()); break;

                case GeoIcon.EyedropperVariant: content = new ColorSpoid().UseViewModel(new ColorSpoidViewModel()); break;

                case GeoIcon.Palette: content = new SwitchSkin().UseViewModel(Skin); break;

                case GeoIcon.Web: content = new Translator().UseViewModel(Translate); break;

                case GeoIcon.Close: Environment.Exit(0); break;

                default: content = new EmptyView(); break;
                }
                content.OnShow(menu);
            }
        }
Пример #12
0
 public static void Clear()
 {
     ModelInstance = null;
     FlowElement   = null;
 }
Пример #13
0
 public void Notify(IBaseDelegateExecution execution)
 {
     ModelInstance = ((IDelegateExecution)execution).BpmnModelInstance;
     FlowElement   = ((IDelegateExecution)execution).BpmnModelElementInstance;
 }
Пример #14
0
 private static Type getInterfaceType(IFlowElement element, string name)
 {
     Type[] interfaces = element.GetType().GetInterfaces();
     return(interfaces.FirstOrDefault((t) => { return t.Name.ToLower().StartsWith(name.ToLower()); }));
 }
Пример #15
0
 internal static Type GetIDoneType(this IFlowElement element)
 {
     return(getGenericInterfaceType(element, "IDone"));
 }
Пример #16
0
        /// <summary>
        /// Registers a method in the flow.
        /// </summary>
        /// <typeparam name="T">The type of the input parameter of the method.</typeparam>
        /// <typeparam name="TResult">The type of the return value of the method.</typeparam>
        /// <param name="method">The method to register.</param>
        /// <param name="onDone">Optional method that is executed after the method has finished successfully (e.g. logging or branching).</param>
        /// <param name="onFail">Optional method that is executed after the method has finished with an error (e.g. logging or branching).</param>
        /// <param name="onAlways">Optional method that is executed after the method has finished (e.g. logging or branching).</param>
        /// <exception cref="Simple.Messaging.FlowRegisterException">Occurs if the input type provided does not match the return type of the previous method.</exception>
        public void Register <T, TResult>(Func <T, TResult> method, Action <TResult> onDone = null, Action <Exception> onFail = null, Action onAlways = null)
        {
            IFlowElement f = register <T>(new Function <T, TResult>(method));

            registerAdditionalEvents <TResult>(ref f, onDone, onFail, onAlways);
        }
Пример #17
0
 /// <summary>
 /// Register an error that occurred while working with this
 /// instance.
 /// </summary>
 /// <param name="ex">
 /// The exception that occurred.
 /// </param>
 /// <param name="flowElement">
 /// The flow element that the exception occurred in.
 /// </param>
 public void AddError(Exception ex, IFlowElement flowElement)
 {
     AddError(ex, flowElement, true, true);
 }
Пример #18
0
        /// <summary>
        /// Registers a method in the flow.
        /// </summary>
        /// <typeparam name="T">The type of the input parameter of the method.</typeparam>
        /// <param name="method">The method to register.</param>
        /// <param name="onDone">Optional method that is executed after the method has finished successfully (e.g. logging or branching).</param>
        /// <param name="onFail">Optional method that is executed after the method has finished with an error (e.g. logging or branching).</param>
        /// <param name="onAlways">Optional method that is executed after the method has finished (e.g. logging or branching).</param>
        /// <exception cref="Simple.Messaging.FlowRegisterException">Occurs if the type provided does not match the return type of the previous method.</exception>
        public void Register <T>(Action <T> method, Action onDone = null, Action <Exception> onFail = null, Action onAlways = null)
        {
            IFlowElement f = register <T>(new NoRetrunFunction <T>(method));

            registerAdditionalEvents(ref f, onDone, onFail, onAlways);
        }
 public static void Clear()
 {
     UserTask      = null;
     ModelInstance = null;
 }
 public virtual void Notify(IDelegateTask delegateTask)
 {
     ModelInstance = delegateTask.BpmnModelInstance;
     UserTask      = delegateTask.BpmnModelElementInstance;
 }
Пример #21
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="ex">
 /// The exception
 /// </param>
 /// <param name="flowElement">
 /// The flow element that the exception occurred in or is related to.
 /// </param>
 /// <param name="shouldThrow">
 /// Set whether the pipeline should throw this exception.
 /// </param>
 public FlowError(Exception ex, IFlowElement flowElement, bool shouldThrow = true)
 {
     ExceptionData = ex;
     FlowElement   = flowElement;
     ShouldThrow   = shouldThrow;
 }
Пример #22
0
        /// <summary>
        /// Create a new <see cref="IFlowElement"/> using the specified
        /// <see cref="ElementOptions"/> and add it to the supplied list
        /// of elements.
        /// </summary>
        /// <param name="elements">
        /// The list to add the new <see cref="IFlowElement"/> to.
        /// </param>
        /// <param name="elementOptions">
        /// The <see cref="ElementOptions"/> instance to use when creating
        /// the <see cref="IFlowElement"/>.
        /// </param>
        /// <param name="elementLocation">
        /// The string description of the element's location within the
        /// <see cref="PipelineOptions"/> instance.
        /// </param>
        private void AddElementToList(
            List <IFlowElement> elements,
            ElementOptions elementOptions,
            string elementLocation)
        {
            // Check that a builder name is set
            if (string.IsNullOrEmpty(elementOptions.BuilderName))
            {
                throw new PipelineConfigurationException(
                          $"A BuilderName must be specified for " +
                          $"{elementLocation}.");
            }

            // Try to get the builder to use
            var builderType = GetBuilderType(elementOptions.BuilderName);

            if (builderType == null)
            {
                throw new PipelineConfigurationException(
                          $"Could not find builder matching " +
                          $"'{elementOptions.BuilderName}' for " +
                          $"{elementLocation}. Available builders are: " +
                          $"{string.Join(",", _elementBuilders.Select(t => t.Name))}");
            }

            // Get the methods on the builder
            var buildMethods = builderType.GetRuntimeMethods()
                               .Where(m => m.Name == "Build");

            // If there are no 'Build' methods or if there is no default
            // constructor then throw an error.
            if (buildMethods.Any() == false)
            {
                throw new PipelineConfigurationException(
                          $"Builder '{builderType.FullName}' for " +
                          $"{elementLocation} has no 'Build' methods.");
            }

            object builderInstance = null;

            if (_services != null)
            {
                // Try to get a a builder instance from the service collection.
                builderInstance = _services.GetRequiredService(builderType);
            }
            else
            {
                // A service collection does not exist in the builder, so try
                // to construct a builder instance from the assemblies
                // currently loaded.
                builderInstance = GetBuilderFromAssemlies(builderType);
                if (builderInstance == null)
                {
                    throw new PipelineConfigurationException(
                              $"Builder '{builderType.FullName}' for " +
                              $"{elementLocation} does not have a default constructor. " +
                              $"i.e. One that takes no parameters. Or a constructor " +
                              $"which takes an ILoggerFactory parameter.");
                }
            }
            // Holds a list of the names of parameters to pass to the
            // build method when we're ready.
            List <string> buildParameterList = new List <string>();

            if (elementOptions.BuildParameters != null)
            {
                // Call any non-build methods on the builder to set optional
                // parameters.
                buildParameterList = ProcessBuildParameters(
                    elementOptions.BuildParameters,
                    builderType,
                    builderInstance,
                    elementLocation);
            }

            // At this point, all the optional methods on the builder
            // have been called and we're ready to call the Build method.
            // If there are no matching build methods or multiple possible
            // build methods based on our parameters then throw an exception.
            var possibleBuildMethods = buildMethods.Where(m =>
                                                          m.GetParameters().Length == buildParameterList.Count &&
                                                          m.GetParameters().All(p => buildParameterList.Contains(p.Name.ToUpperInvariant())));

            StringBuilder buildSignatures = new StringBuilder();

            buildSignatures.AppendLine();
            foreach (var method in buildMethods)
            {
                buildSignatures.AppendLine(string.Join(",",
                                                       method.GetParameters().Select(p =>
                                                                                     $"{p.Name} ({p.ParameterType.Name})")));
            }

            if (possibleBuildMethods.Any() == false)
            {
                StringBuilder methodSignatures = new StringBuilder();
                methodSignatures.AppendLine();
                // Build a list of the 'set' methods on this builder
                // along with their parameter.
                foreach (var method in builderType.GetRuntimeMethods()
                         // Include any methods that are:
                         // 1. public
                         // 2. have a single parameter
                         .Where(m => m.IsPublic && m.GetParameters().Length == 1 &&
                                m.DeclaringType.Name.ToUpperInvariant().Contains("BUILDER")))
                {
                    methodSignatures.AppendLine($"{method.Name} ({method.GetParameters()[0].GetType().Name})");
                }
                throw new PipelineConfigurationException(
                          $"Builder '{builderType.FullName}' for " +
                          $"{elementLocation} has no " +
                          $"'Set' methods or 'Build' methods that match " +
                          $"(case-insensitively) the following parameters: " +
                          $"{string.Join(",", buildParameterList)}. " +
                          $"The available configuration methods on this builder are: " +
                          $"{methodSignatures.ToString()}" +
                          $"The available 'Build' methods have the following signatures: " +
                          $"{buildSignatures.ToString()}");
            }
            else if (possibleBuildMethods.Count() > 1)
            {
                throw new PipelineConfigurationException(
                          $"Builder '{builderType.FullName}' for " +
                          $"{elementLocation} has multiple " +
                          $"'Build' methods that match the following parameters: " +
                          $"{string.Join(",", buildParameterList)}. " +
                          $"Matching method signatures are: {buildSignatures.ToString()}");
            }

            // Get the build method parameters and add the configured
            // values to the parameter list.
            List <object> parameters  = new List <object>();
            var           buildMethod = possibleBuildMethods.Single();
            var           caseInsensitiveParameters = elementOptions.BuildParameters
                                                      .ToDictionary(d => d.Key.ToUpperInvariant(), d => d.Value);

            foreach (var parameterInfo in buildMethod.GetParameters())
            {
                var    paramType  = parameterInfo.ParameterType;
                object paramValue = caseInsensitiveParameters[parameterInfo.Name.ToUpperInvariant()];
                if (paramType != typeof(string))
                {
                    paramValue = ParseToType(paramType,
                                             (string)paramValue,
                                             $"Method 'Build' on builder " +
                                             $"'{builderType.FullName}' for " +
                                             $"{elementLocation} expects a parameter of type " +
                                             $"'{paramType.Name}'");
                }
                parameters.Add(paramValue);
            }
            // Call the build method with the parameters we set up above.
            object result = buildMethod.Invoke(builderInstance, parameters.ToArray());

            if (result == null)
            {
                throw new PipelineConfigurationException(
                          $"Failed to build {elementLocation} using " +
                          $"'{builderType.FullName}', reason unknown.");
            }
            IFlowElement element = result as IFlowElement;

            if (element == null)
            {
                throw new PipelineConfigurationException(
                          $"Failed to cast '{result.GetType().FullName}' to " +
                          $"'IFlowElement' for {elementLocation}");
            }

            // Add the element to the list.
            elements.Add(element);
        }