- 15 Mar 2022
- 5 Minutes to read
- Print
- DarkLight
SDK: Creating Custom Flow and Rule Behavior
- Updated on 15 Mar 2022
- 5 Minutes to read
- Print
- DarkLight
Overview
Flows in Decisions can be assigned a Flow Behavior which acts like an interface definition for a Flow. It can enforce expected inputs and outputs as well as create theose expected inputs when the behavior is assigned.
Decisions comes with several prebuilt Flow behaviors, but developers may create and implement custom Flow behaviors to improve a process.
Custom Flow Behavior Methods
To create a new Flow behavior, create a public class that inherits from DefaultFlowBehavior. This provides a number of methods and properties available for configuration.
OnBehaviorAssigned
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);
This code runs when the behavior is assigned to a Flow. This method edits the Flow as desired.
The below examples utilizes this method to add input data to a Flow and to add a tag to the Flow for quicker searching for the behavior.
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 to declare special inputs that are only visible inside your Flow.
Whereas inputs normally get their value by mapping data into the Flow, these inputs retrieve their values from code ran through the ProcessInputValues method. These inputs are not visible outside of the Flow, but the inputs' data is consumable inside the Flow.
An example may include passing only a simple data such as an ID into a Flow while connecting complex data like the object associated with that ID available in the Flow. In this example, the built Flow behavior takes in only a user ID, but Flow contains the full user object available for use.
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 works in conjunction with the ProcessInputsDelcaration method. This method executes at runtime to populate the values of the inputs declared by ProcessInputDeclaration.
In the example below, the 'User Id to Process' input value allows users to search for 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 to validate anything about the Flow. Validation issues are assigned to steps since it is a ValidationIssue data type.
An example use of this method may ensure that the Flow contains its 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>
In addition to the other methods, DefaultFlowBehavrior 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
The DefaultOutputs method defines the expected output data and its outcome paths. This should be used in conjunction with ConstrainFlowOutputs to cause validation warnings when the defined defaults are not met.
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
Configuring this property to True causes validation warnings on the end steps in a Flow if 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
This property toggles whether or not this 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; however, it can still be selected in any custom 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 name. This name displays in the portal UI once a user sets the Flow behavior for a Flow.
If left blank, the name defaults to the full class.
Default Value: 'Default Flow Behavior'
Example Override:
public override string Name
{
get
{
return "My Behavior Flow";
}
}
OnlySyncSteps
When set to true, this property forces the Flow to only allow Sync steps. This should be used on Flows with responses expected to return synchronously.
Default Value: False
Example Override:
public override bool OnlySyncSteps
{
get
{
return true;
}
}
OverrideDebugUIClassName
The OverrideDebugUIClassName property allows developers to specify a different debugger UI when it runs.
Default Value: null
Since this is an advanced property that varies greatly for each specific use case, no example override is provided.
ShowFlowInputs
When set to true, this property hides the Inputs section of the Flow's property editor. This can block Designers from editing the inputs already defined in the Flow behavior.
Default Value: True
Example Override:
public override bool ShowFlowInputs
{
get
{
return false;
}
}
Custom Rule 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; }
}