/// <summary> /// Extracts all consequences of a message being handled. /// </summary> /// <remarks> /// Keeps track of all <paramref name="services"/> that are passed with interactions. /// </remarks> public Interactions ExtractConcequences(TypeDescription originatingMessage, List <string> services, string previousService = null, string inAlternativeFlow = null, List <ArgumentDescription> arguments = null) { var result = new Interactions(); var handlers = Program.Types.HandlersFor(originatingMessage); foreach (var handler in handlers) { var levelName = Service(handler); var source = previousService ?? "A"; var target = levelName ?? "Q"; var arrow = new Arrow { Source = source, Target = target, Name = originatingMessage.Name, Color = ArrowColor(originatingMessage) }; result.AddFragment(arrow); if (!activations.Contains(levelName)) { activations.Push(levelName); } if (!services.Contains(target)) { services.Add(target); } var statements = HandlingMethod(handler, originatingMessage).Statements; foreach (var statement in statements) { var statementInteractions = TraverseBody(services, handler, previousService ?? levelName, statement, inAlternativeFlow ?? levelName); if (statementInteractions.Fragments.Count > 0) { result.AddFragments(statementInteractions.Fragments); } } if (activations.Count > 0 && activations.Peek() == levelName && levelName != inAlternativeFlow) { activations.Pop(); } } return(result); }
/// <summary> /// Traverse the statement and look of resulting interactions that are relevant for the sequence diagram. /// </summary> /// <remarks> /// Tracks flow over services, even if the same service becomes part of a different resulting event. /// </remarks> private Interactions TraverseBody(List <string> services, TypeDescription handler, string serviceName, Statement statement, string inAlternativeFlow) { switch (statement) { case InvocationDescription invocation when IsMessageCreation(invocation): var message = Program.Types.First(invocation.Arguments.Skip(invocation.Name == "RaiseEvent" ? 0 : 1).First().Type); return(ExtractConcequences(message, services, Service(handler), inAlternativeFlow, invocation.Arguments)); case InvocationDescription invocation: { var result = new Interactions(); var consequences = Program.Types.GetInvocationConsequenceStatements2(invocation).Where(s => s != invocation); foreach (var consequence in consequences) { var invocationInteractions = TraverseBody(services, handler, serviceName, consequence, inAlternativeFlow); if (invocationInteractions.Fragments.Count > 0) { result.AddFragments(invocationInteractions.Fragments); } } return(result); } case ForEach forEachStatement: { var result = new Interactions(); var interactions = new List <InteractionFragment>(); foreach (var invocation in forEachStatement.Statements) { var invocationInteractions = TraverseBody(services, handler, serviceName, invocation, inAlternativeFlow); if (invocationInteractions.Fragments.Count > 0) { interactions.AddRange(invocationInteractions.Fragments); } } if (interactions.Count > 0) { var alt = new Alt(); var altSection = new AltSection(); altSection.AddFragments(interactions); altSection.GroupType = "forEach"; altSection.Label = forEachStatement.Expression; alt.AddSection(altSection); result.AddFragment(alt); } return(result); } case Switch switchStatement: { var result = new Interactions(); var alt = new Alt(); foreach (var section in switchStatement.Sections) { var interactions = new List <InteractionFragment>(); foreach (var invocation in section.Statements) { var invocationInteractions = TraverseBody(services, handler, serviceName, invocation, inAlternativeFlow); if (invocationInteractions.Fragments.Count > 0) { interactions.AddRange(invocationInteractions.Fragments); } } if (interactions.Count > 0) { var altSection = new AltSection(); if (alt.Sections.Count == 0) { altSection.GroupType = "case"; } ; altSection.AddFragments(interactions); altSection.Label = section.Labels.Aggregate(string.Empty, (s1, s2) => s1 + s2); alt.AddSection(altSection); } } if (alt.Sections.Count > 0) { result.AddFragment(alt); } return(result); } case If ifStatement: { var result = new Interactions(); var alt = new Alt(); foreach (var section in ifStatement.Sections) { var interactions = new List <InteractionFragment>(); foreach (var invocation in section.Statements) { var invocationInteractions = TraverseBody(services, handler, serviceName, invocation, inAlternativeFlow); if (invocationInteractions.Fragments.Count > 0) { interactions.AddRange(invocationInteractions.Fragments); } } if (interactions.Count > 0) { var altSection = new AltSection(); if (alt.Sections.Count == 0) { altSection.GroupType = "if"; } ; altSection.AddFragments(interactions); altSection.Label = section.Condition; alt.AddSection(altSection); } } if (alt.Sections.Count > 0) { result.AddFragment(alt); } return(result); } } return(new Interactions()); }