/// <summary>
 /// This method gets activities that have inbound connections.
 /// </summary>
 /// <remarks>
 /// <para>
 /// "Start activities" are those with no inbound connections; IE no workflow connection-target will point to a start activity.
 /// What this method returns is essentially a blacklist of activity IDs which are not starting activities.
 /// </para>
 /// </remarks>
 /// <param name="compositeActivityBlueprint">A composite activity blueprint</param>
 /// <returns>A lookup of activity IDs which are not starting activities</returns>
 ILookup <string?, string?> GetAllActivityIdsWhichHaveInboundConnections(ICompositeActivityBlueprint compositeActivityBlueprint)
 {
     return(compositeActivityBlueprint.Connections
            .Select(x => x.Target.Activity?.Id)
            .Distinct()
            .ToLookup(x => x));
 }
        private IActivityBlueprint BuildActivityBlueprint(IActivityBuilder builder, ICompositeActivityBlueprint parent)
        {
            var isComposite = typeof(CompositeActivity).IsAssignableFrom(builder.ActivityType);

            return(isComposite
                ? new CompositeActivityBlueprint(builder.ActivityId, parent, GetCompositeName(builder.Name), builder.DisplayName, builder.Description, builder.ActivityTypeName, builder.PersistWorkflowEnabled, builder.LoadWorkflowContextEnabled,
                                                 builder.SaveWorkflowContextEnabled, builder.PropertyStorageProviders, builder.Source)
                : new ActivityBlueprint(builder.ActivityId, parent, GetCompositeName(builder.Name), builder.DisplayName, builder.Description, builder.ActivityTypeName, builder.PersistWorkflowEnabled, builder.LoadWorkflowContextEnabled,
                                        builder.SaveWorkflowContextEnabled, builder.PropertyStorageProviders, builder.Source));
        }
        /// <summary>
        /// Gets a collection of the starting activities for the specified composite activity blueprint.
        /// </summary>
        /// <param name="compositeActivityBlueprint">A composite activity blueprint</param>
        /// <returns>A collection of the blueprint's starting activities</returns>
        public IEnumerable <IActivityBlueprint> GetStartActivities(ICompositeActivityBlueprint compositeActivityBlueprint)
        {
            var activityIdsThatAreNotStartingActivities = GetAllActivityIdsWhichHaveInboundConnections(compositeActivityBlueprint);

            var query = from activity in compositeActivityBlueprint.Activities
                        where !activityIdsThatAreNotStartingActivities.Contains(activity.Id)
                        select activity;

            return(query);
        }
        private static IEnumerable <string> GetInboundActivityPathInternal(this ICompositeActivityBlueprint workflowBlueprintBlueprintInstance, string activityId, HashSet <string> inspectedActivityIds)
        {
            foreach (var connection in workflowBlueprintBlueprintInstance.GetInboundConnections(activityId))
            {
                // Circuit breaker: Detect workflows that implement repeating flows to prevent an infinite loop here.
                if (inspectedActivityIds.Contains(connection.Source.Activity.Id))
                {
                    yield break;
                }

                yield return(connection.Source.Activity.Id);

                foreach (var parentActivityId in workflowBlueprintBlueprintInstance.GetInboundActivityPathInternal(connection.Source.Activity.Id, inspectedActivityIds).Distinct())
                {
                    inspectedActivityIds.Add(parentActivityId);
                    yield return(parentActivityId);
                }
            }
        }
        /// <summary>
        /// Gets a collection of the starting activities for the specified composite activity blueprint.
        /// </summary>
        /// <param name="compositeActivityBlueprint">A composite activity blueprint</param>
        /// <returns>A collection of the blueprint's starting activities</returns>
        public IEnumerable <IActivityBlueprint> GetStartActivities(ICompositeActivityBlueprint compositeActivityBlueprint)
        {
            if (!compositeActivityBlueprint.Activities.Any())
            {
                return(Enumerable.Empty <IActivityBlueprint>());
            }

            var activityIdsThatAreNotStartingActivities = GetAllActivityIdsWhichHaveInboundConnections(compositeActivityBlueprint);

            var query = from activity in compositeActivityBlueprint.Activities
                        where !activityIdsThatAreNotStartingActivities.Contains(activity.Id)
                        select activity;

            var list = query.ToList();

            if (list.Any())
            {
                return(list);
            }

            var first = compositeActivityBlueprint.Activities.First();

            return(new[] { first });
        }
 public static IEnumerable <IActivityBlueprint> GetStartActivities <T>(this IGetsStartActivitiesForCompositeActivityBlueprint startActivitiesProvider,
                                                                       ICompositeActivityBlueprint workflowBlueprint) where T : IActivity
 => startActivitiesProvider.GetStartActivities(workflowBlueprint, typeof(T));
 public static IEnumerable <IActivityBlueprint> GetStartActivities(this IGetsStartActivitiesForCompositeActivityBlueprint startActivitiesProvider,
                                                                   ICompositeActivityBlueprint workflowBlueprint,
                                                                   Type activityType)
 => startActivitiesProvider.GetStartActivities(workflowBlueprint, activityType.Name);
 public static IEnumerable <IActivityBlueprint> GetStartActivities(this IGetsStartActivitiesForCompositeActivityBlueprint startActivitiesProvider,
                                                                   ICompositeActivityBlueprint workflowBlueprint,
                                                                   string activityType)
 => startActivitiesProvider.GetStartActivities(workflowBlueprint).Where(x => x.Type == activityType);
 public static IEnumerable <IActivityBlueprint> GetEndActivities(this ICompositeActivityBlueprint workflowBlueprint) => workflowBlueprint.Activities.Where(x => !workflowBlueprint.GetOutboundConnections(x.Id).Any());
        /// <summary>
        /// Returns the full path of incoming activities.
        /// </summary>
        public static IEnumerable <string> GetInboundActivityPath(this ICompositeActivityBlueprint workflowBlueprint, string activityId)
        {
            var inspectedActivityIds = new HashSet <string>();

            return(workflowBlueprint.GetInboundActivityPathInternal(activityId, inspectedActivityIds).Distinct().ToList());
        }
        public static IEnumerable <IConnection> GetInboundConnectionPath(this ICompositeActivityBlueprint workflowBlueprint, string activityId)
        {
            var inspectedActivityIds = new HashSet <string>();

            return(workflowBlueprint.GetInboundConnectionPathInternal(activityId, inspectedActivityIds));
        }
 public static IEnumerable <IConnection> GetOutboundConnections(this ICompositeActivityBlueprint workflowBlueprint, string activityId) =>
 workflowBlueprint.Connections.Where(x => x.Source.Activity.Id == activityId).ToList();
 public static IEnumerable <IActivityBlueprint> GetBlockingActivities(this ICompositeActivityBlueprint workflowBlueprint, WorkflowInstance workflowInstance) =>
 workflowBlueprint.Activities.Where(activity => workflowInstance.BlockingActivities.Select(x => x.ActivityId).Contains(activity.Id));
 public static IEnumerable <IActivityBlueprint> GetActivities(this ICompositeActivityBlueprint workflowBlueprint, IEnumerable <string> ids) => workflowBlueprint.Activities.Where(x => ids.Contains(x.Id));
 public static IActivityBlueprint?GetActivity(this ICompositeActivityBlueprint workflowBlueprint, string id) => workflowBlueprint.Activities.FirstOrDefault(x => x.Id == id);