- 18 Aug 2021
- 5 Minutes to read
- Print
- DarkLight
SDK: Creating Custom Flow Behavior
- Updated on 18 Aug 2021
- 5 Minutes to read
- Print
- DarkLight
Overview
Flows in Decisions can be assigned something called a Flow Behavior. A Flow Behavior acts like an interface definition for a flow. It can enforce expected inputs and outputs as well as create the expected inputs when the behavior is assigned.
Custom Flow Behavior
To create a new Flow behavior, create a public class that inherits from DefaultFlowBehavior to provide a number of methods and properties to override to create the desired Flow behavior.
Flow behavior methods:
public virtual void OnBehaviorAssigned(Flow f)
public virtual DataDescription[] ProcessInputDeclaration(Flow flow, DataDescription[] inputData);
public virtual void ProcessInputValues(Flow flow, FlowStateData data);
public virtual DataDescription[] ProcessStepInputDeclaration(FlowStep step, DataDescription[] inputs);
public virtual FlowStepToolboxInformation[] ProcessSteps(Flow flow, string[] nodes, FlowStepToolboxInformation[] steps);
public virtual ValidationIssue[] RunFlowValidation(Flow flow);
OnBehaviorAssigned
This code is run when the behavior is assigned to a Flow. Use this method to make any kind of manipulation to the Flow.
Default Behavior: Nothing is done
Example Override of this Method:
public override void OnBehaviorAssigned(Flow f)
{
//Set inputs on this flow
List<flowinputdatadescription> inputs = new List<flowinputdatadescription>();
DecisionsType decTypeString = new DecisionsNativeType(typeof(string));
inputs.Add(FlowInputDataDescription.Create(new DataDescription(decTypeString, INPUT_NAME_USER_ID)));
f.Input = inputs.ToArray();
//Set tag on this flow
AbstractUserContext userContext = new SystemUserContext();
tring flowBehaviorTag = "My Sample Behavior Flow";
string[] existingTags = TaggingService.Instance.GetTags(userContext, f.Id, typeof(ElementRegistration).FullName);
{
if (ArrayUtilities.IsEmpty(existingTags) || !existingTags.Contains(flowBehaviorTag))
{
TaggingService.Instance.AddTag(userContext, f.Id, typeof(ElementRegistration).FullName, typeof(ElementRegistration).Name, flowBehaviorTag);
}
}
}</flowinputdatadescription></flowinputdatadescription>
ProcessInputDeclaration
This method is used in conjunction with the ProcessInputValues method. In this method, declare special inputs that are only visible inside a Flow. Whereas regular inputs get their value from data being mapping into the Flow, these inputs get their value from code which is run in the ProcessInputValues method. These inputs are not seen from the outside of the Flow, but the data of these inputs is consumable inside the Flow. An example use case for this functionality would be one where a user would only want to hand in only a simple piece of data (like an ID) into a Flow, but to have complex data (like the object associated with that id) available in the Flow. In the following code example, the Flow behavior takes in only a user ID, but inside the Flow has a full user object available to be used.
Default Behavior: No inputs are modified.
Example Override of this Method
public override DataDescription[] ProcessInputDeclaration(Flow flow, DataDescription[] inputData)
{
if (flow == null)
{
throw new Exception("flow not specified");
}
if (inputData == null)
{
inputData = new DataDescription[0];
}
List<datadescription> inputs = new List<datadescription>(inputData);
DecisionsType decType = DataStructureService.Instance.GetDecisionsTypeByFullName(new SystemUserContext(), typeof(Account).FullName);
inputs.Add(new DataDescription(decType, "User Account to Process"));
return inputs.ToArray();
}</datadescription></datadescription>
ProcessInputValues
As mentioned above, this method should be used in conjunction with the ProcessInputsDelcaration method. This method is executed at runtime and is used to populate the values of the inputs declared by ProcessInputDeclaration. In the example below, the User Id to Process input value is used to look up the value for User Account to Process.
Default Behavior: Do nothing
Example Override of this Method:
public override void ProcessInputValues(Flow flow, FlowStateData data)
{
Account accountToProcess = AccountService.Instance.GetByID(new SystemUserContext(), data["User Id to Process"].ToString());
data["User Account to Process"] = accountToProcess;
}
RunFlowValidation
This method returns an array of validation issues. Validation issues are assigned to steps (this is part of the ValidationIssue data type definition). Use this method to validate anything about the Flow. The following code example shows how this can be used to ensure that the Flow has the expected inputs.
Default Behavior: No validation issues are checked for or returned.
Example Override of this Method:
public override ValidationIssue[] RunFlowValidation(Flow flow)
{
// check that the flow only has correct inputs
List<validationissue> validationIssues = new List<validationissue>();
if (flow.InputData != null && flow.InputData.Length == 1)
{
if (flow.InputData[0].Type is DecisionsNativeType && ((DecisionsNativeType)flow.Input[0].Type).ToNativeType() == typeof(string))
{
return validationIssues.ToArray();
}
}
FlowStep startStep = flow.GetStepsOfType(typeof(StartStep)).FirstOrDefault();
validationIssues.Add(new ValidationIssue(startStep, "This flow must have only one String input"));
return validationIssues.ToArray();
}</validationissue></validationissue>
DefaultFlowBehavior Overridden Properties
In addition to methods, DefaultFlowBehavior also has properties that can be overridden.
public virtual bool ConstrainFlowOutputs { get; }
public virtual OutcomeScenarioData[] DefaultOutputs { get; }
public virtual bool IsUserSettable { get; }
public virtual string Name { get; }
public virtual bool OnlySyncSteps { get; }
public virtual string OverrideDebugUIClassName { get; }
public virtual bool ShowFlowInputs { get; }
DefaultOutputs
Allows a user to define the expected output paths and output data in those paths.
Default Value: null
Example Override:
public override OutcomeScenarioData[] DefaultOutputs
{
get
{
return new OutcomeScenarioData[] {
new OutcomeScenarioData("Done",new DataDescription[] { new DataDescription(new DecisionsNativeType(typeof(string)), "My Result", false, true, false)}) };
}
}
ConstrainFlowOutputs
Setting to true causes validation warnings on the End steps on a Flow when the End steps' outputs don't match those as defined in the DefaultOutputs property.
Default Value: false
Example Override:
public override bool ConstrainFlowOutputs
{
get
{
return true;
}
}
IsUserSettable
Sets whether or not the Flow behavior shows up in the Decisions Portal UI when a user sets the behavior of a Flow. When set to false, this behavior will not show up in the behavior list for users to select from, but can still be used by code to set Flow behaviors on Flows.
Default Value: true
Example Override:
public override bool IsUserSettable
{
get { return false; }
}
Name
Use this property to give the Flow behavior a friendly name. This name will be displayed in the portal UI when a user sets the Flow behavior for a Flow. If not set, the name will show up as the full class.
Default Value: "Default Flow Behavior"
Example Override:
public override string Name
{
get
{
return "My Behavior Flow";
}
}
OnlySyncSteps
This property when set to true, forces the Flow to only be allowed to contain Sync steps. This should be used on Flows where the user expects the Flow's response to return synchronously.
Default Value: false
Example Override:
public override bool OnlySyncSteps
{
get
{
return true;
}
}
OverrideDebugUIClassName
This is an advanced property that allows a user to specify a different UI to be presented when the debugger is run. If this is a requirement, please contact professional services for help with implementation.
Default Value: null
ShowFlowInputs
Description: When set to true, this property hides the Inputs section of the flow's property editor. This can be used to block Designers from editing the inputs that you have defined in your flow behavior.
Default Value: true
Example Override:
public override bool ShowFlowInputs
{
get
{
return false;
}
}
Custom Flow Behavior
IRuleBehavior, much like IFlowBehavior allows for the customization of the behavior of the rule editor.
public interface IRuleBehavior
{
string Name { get; }
bool IsUserSettable { get; }
string RewriteSubject(Rule r, string subject);
string RewriteVerb(Rule r, string verb);
string RewritePredicate(Rule r, IRuleStep step, DataDescription anchorData, IInputMapping[] mappings, string predicate);
DataDescription[] ProcessTreeInputDeclaration(Rule r, string path, DataDescription[] inputs);
DataDescription[] ProcessStepInputDeclaration(RuleStep step, DataDescription[] inputs);
DataDescription[] ProcessInputDeclaration(Rule r, DataDescription[] inputData);
FlowStepToolboxInformation[] ProcessSteps(Rule r, DataDescription anchorData, string[] nodes, FlowStepToolboxInformation[] steps);
ValidationIssue[] RunRuleValidation(Rule rule);
void ProcessInputValues(Rule r, FlowStateData data);
string OverrideDebugUIClassName { get; }
string OverrideRunUIClassName { get; }
AllowUserToEditRuleInputData { get; }
void OnBehaviorAssigned(Rule r);
bool CanChangeBehavior { get; }
bool CanChangeRuleType { get; }
bool AllowDirectServiceCall { get; }
}