Calling rule on click of form submit button

Which IIQ version are you inquiring about?

8.4

Share all details about your problem, including any error messages you may have received.

Hi all,

I have a form being called as part of a workflow and I would like on click of the submit button a custom rule will be called. Can anyone kindly advise?

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Form PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Form name="Guest Invite" type="Workflow">
	<Attributes>
        <Map>
            <entry key="title" value="Guest Invite"/>
            <entry key="autoExecute" value="false"/>
            <entry key="executeOnLoad" value="false"/>
            <entry key="formMode" value="edit"/>
            <entry key="nextRule" value="Guest Invite"/>
        </Map>
	</Attributes>
    <Section name="mainSection">
        <Field displayName="Email" name="email" required="true" type="string"/>
		<Field displayName="First Name" name="firstName" required="true" type="string"/>
		<Field displayName="Last Name" name="lastName" required="true" type="string"/>
		<Field displayName="Mobile Number" name="mobileNumber" required="true" type="string"/>
		<Field displayName="Username" name="username" required="true" type="string"/>
    </Section>
	 <Button action="next" label="Submit"/>
	<Button action="cancel" label="Cancel"/>
</Form>
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Workflow PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Workflow explicitTransitions="true" name="Self Service View Workflow">
  <Variable editable="true" input="true" name="launcher">
    <Description>Launcher name.</Description>
  </Variable>
  <Variable initializer="true" name="transient"/>
  <Variable initializer="true" name="trace">
    <Description>Used for debugging this workflow and when set to true trace
      will be sent to stdout.</Description>
  </Variable>
  <Step icon="Start" name="Start" posX="229" posY="21">
    <Transition to="Display Form"/>
  </Step>
  <Step icon="Approval" name="Display Form" posX="427" posY="21">
    <Approval mode="serial" name="Display Form" owner="ref:launcher">
      <Arg name="workItemType" value="Form"/>
      <Arg name="workItemDescription" value="Guest Account Invite"/>
      <Arg name="workItemForm" value="string:Guest Invite"/>
      <Arg name="workItemFormBasePath"/>
    </Approval>
    <Description>
       Display the Service Account form .
    </Description>
    <Transition to="Stop"/>
  </Step>
  <Step icon="Stop" name="Stop" posX="611" posY="21"/>
</Workflow>

Hi @shijingg ,

I think it can be done two ways .
Approach 1 - whatever you want to do , put that functionality in a method . Reference that rule in this workflow using below tags after variables -

<RuleLibraries>
    <Reference class="sailpoint.object.Rule"  name="Rule Name"/>
  </RuleLibraries>

On the basis of the form action button call that particular method . It should get the work done .
Approach 2 - You can call the rule using runrule api from workflow source . below is the code snippet which can be used for same -

HashMap ruleContext = new HashMap();
ruleContext.put( "context", context );
ruleContext.put( "log", log );
ruleContext.put("anothervariable",anothervalue);
Rule rule = context.getObject( Rule.class, ruleName );
Object o = context.runRule( rule, ruleContext );

See if it helps , we can brainstorm further if needed . Thanks.

Hi @shijingg

You can create another step (say “Execute Rule”) after Display Form step. Add a transition to Execute Rule step when form is submitted.

<Transition to="Execute Rule" when="approved"/>

In newly created step, you can execute the rule in any of ways as mentioned by @harsh_gupta4

Thanks,
Harshith

Hi @harsh_gupta4 @tharshith,

I managed to call the rule, but the issue now is I am unable to read the form inputs in my rule. Any advice?

Hi @shijingg ,

define the signature with inputs in your Rule as per below example -

<Description>Test Rule</Description>
  <Signature>
    <Inputs>
       <Argument name="log">
        <Description>
          The log object associated with the SailPointContext.
        </Description>
      </Argument>
      <Argument name="context">
        <Description>
          A sailpoint.api.SailPointContext object that can be used to query the database if necessary.
        </Description>
      </Argument>
      <Argument name="var1">
        <Description>
          test variables
        </Description>
      </Argument>
      <Argument name="var2">
        <Description>
          test variables
        </Description>
      </Argument>
    </Inputs>
  </Signature>

Gather the data from Form in Workflow and pass in the rule in these variables . Below is the sample code -

HashMap ruleContext = new HashMap();
ruleContext.put( "context", context );
ruleContext.put( "log", log );
ruleContext.put("var1","TestValue1");
ruleContext.put("var2","TestValue2");
Rule rule = context.getObject( Rule.class, ruleName );
Object o = context.runRule( rule, ruleContext );

Use var1 and var2 in your rule according to your logic .

Thanks.

Hi @harsh_gupta4 , the code you shared is to be placed in the rule? However, from the workflow/form what do I need to do to pass the value down to the rule.

The order is Workflow → Form → Rule?

The part I am not able to do is the rule reading the form values

Hi @shijingg ,

The code which i have shared place in to workflow , Follow below steps -

Step 1 - whatever form you defined in workflow , it should have return values . once form get actioned , set those values in workflow variable.
Step2 - Create a new step in workflow .
Step3 - In Workflow step put the code i provided , pass those variables in place of “var1” and “var2” etc . as per your naming convention.

it should execute the rule and pass those variables in the Rule .

Hi @harsh_gupta4 , do you have a simple example to share? For all 3 components? I’m still quite confused because I am unable to retrieve the values from the form submitted in the rule.

Hi @shijingg,

Please verify if you are returning the values from the form.

When you click on the submit (next) button in the form, lastApprovalState gets populated with “Finished” value and “approved” variable is set to true.

you can use the above variables in the transitions according to your requirements.

Here is sample code, you can modify it according to your requirements.

Workflow:

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Workflow PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Workflow explicitTransitions="true" name="Sample Dynamic Form Workflow">
  <Variable initializer="true" input="true" name="trace"/>
  <Step icon="Start" name="Start" posX="36" posY="82">
    <Transition to="Display Form"/>
  </Step>
  <Step icon="Stop" name="Stop" posX="342" posY="76"/>
  <Step icon="Default" name="Display Form" posX="128" posY="84">
    <Approval name="Sample Form" owner="script:return context.&#9;getUserName();" return="firstname,lastname" send="">
      <Form name="Sample Form">
        <Attributes>
          <Map>
            <entry key="pageTitle" value="Sample Form"/>
          </Map>
        </Attributes>
        <Section name="User Details ">
          <Field displayName="First Name" name="firstname" type="string"/>
          <Field displayName="Last Name" name="lastname" type="string"/>
        </Section>
        <Button action="next" label="Submit"/>
        <Button action="back" label="Back"/>
      </Form>
    </Approval>
    <Transition to="Execute Rule">
      <Script>
        <Source>
boolean result =false;

if(lastApprovalState.equalsIgnoreCase("Finished")){
result  = true;
}

return result</Source>
      </Script>
    </Transition>
    <Transition to="Stop"/>
  </Step>
  <Step action="rule:Sample-FormSubmissionRule" icon="Default" name="Execute Rule" posX="255" posY="140">
    <Transition to="Stop"/>
  </Step>
</Workflow>

Rule:

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Rule language="beanshell" name="Sample-FormSubmissionRule" type="Workflow">
  <Description>A rule used by a Workflow to determine a step action or variable value.

Note that an Attributes map of all variables from the current WorkflowContext, merged with the arguments from the Step, is also passed into the workflow rule.</Description>
  <Signature returnType="Object">
    <Inputs>
      <Argument name="log" type="org.apache.commons.logging.Log">
        <Description>
          The log object associated with the SailPointContext.
        </Description>
      </Argument>
      <Argument name="context" type="sailpoint.api.SailPointContext">
        <Description>
          A sailpoint.api.SailPointContext object that can be used to query the database if necessary.
        </Description>
      </Argument>
      <Argument name="wfcontext">
        <Description>
          The current WorkflowContext.
        </Description>
      </Argument>
      <Argument name="handler">
        <Description>
          The workflow handler associated with the current WorkflowContext.
        </Description>
      </Argument>
      <Argument name="workflow">
        <Description>
          The current Workflow definition.
        </Description>
      </Argument>
      <Argument name="step">
        <Description>
          The current Step.
        </Description>
      </Argument>
      <Argument name="approval">
        <Description>
          The current Approval.
        </Description>
      </Argument>
      <Argument name="item">
        <Description>
          The WorkItem being processed.
        </Description>
      </Argument>
    </Inputs>
    <Returns>
      <Argument name="Object">
        <Description>
          The result of the workflow rule; dependent on the rule itself.
        </Description>
      </Argument>
    </Returns>
  </Signature>
  <Source>
log.info("Entered the Sample-FormSubmissionRule ");

log.info("Submitted firstname : " + firstname);

log.info("Submitted lastname : " + lastname);

log.info("Exited the Sample-FormSubmissionRule");</Source>
</Rule>

Hi @shijingg ,

As code provided by you , I have modified it and put one extra sample rule for your reference which you can replace by your rule . Please note - it is rough code and needs to be further optimized which you can do as per your requirement . I have just quickly wrote down here in community itself so there might be some error , you can test on your end and fix minor issues . below is the end to end sample code -

Form -

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Form PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Form name="Guest Invite" type="Workflow">
	<Attributes>
        <Map>
            <entry key="title" value="Guest Invite"/>
            <entry key="autoExecute" value="false"/>
            <entry key="executeOnLoad" value="false"/>
            <entry key="formMode" value="edit"/>
            <entry key="nextRule" value="Guest Invite"/>
        </Map>
	</Attributes>
    <Section name="mainSection">
        <Field displayName="Email" name="email" required="true" type="string"/>
		<Field displayName="First Name" name="firstName" required="true" type="string"/>
		<Field displayName="Last Name" name="lastName" required="true" type="string"/>
		<Field displayName="Mobile Number" name="mobileNumber" required="true" type="string"/>
		<Field displayName="Username" name="username" required="true" type="string"/>
    </Section>
	 <Button action="next" label="Submit" parameter="buttonActionNext" value="Approve"/>
	<Button action="cancel" label="Cancel" parameter="buttonActionReject" value="Reject"/>
</Form>

Rule -

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Rule language="beanshell" name="Sample-Rule">
<Description>Sample Rule</Description>
  <Signature>
    <Inputs>
       <Argument name="log">
        <Description>
          The log object associated with the SailPointContext.
        </Description>
      </Argument>
      <Argument name="context">
        <Description>
          A sailpoint.api.SailPointContext object that can be used to query the database if necessary.
        </Description>
      </Argument>
      <Argument name="email">
        <Description>
          test variables
        </Description>
      </Argument>
      <Argument name="firstName">
        <Description>
          test variables
        </Description>
      </Argument>
	  <Argument name="lastName">
        <Description>
          test variables
        </Description>
      </Argument>
	  <Argument name="mobileNumber">
        <Description>
          test variables
        </Description>
      </Argument>
	  <Argument name="username">
        <Description>
          test variables
        </Description>
      </Argument>
    </Inputs>
  </Signature>
  <Source>
    <![CDATA[
	//Please put your business Logic
	log.error("email is:: "+email); 
	log.error("firstName is:: "+firstName); 
	log.error("lastName is:: "+lastName); 
	log.error("mobileNumber is:: "+mobileNumber); 
	log.error("username is:: "+username); 
  
  ]]></Source>
</Rule>

Workflow -

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Workflow PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Workflow explicitTransitions="true" name="Self Service View Workflow">
  <Variable editable="true" input="true" name="launcher">
    <Description>Launcher name.</Description>
  </Variable>
  <Variable name="email"/>
  <Variable name="firstName"/>
  <Variable name="lastName"/>
  <Variable name="mobileNumber"/>
  <Variable name="username"/>
  <Variable initializer="true" name="trace">
    <Description>Used for debugging this workflow and when set to true trace
      will be sent to stdout.</Description>
  </Variable>
  <Step icon="Start" name="Start" posX="229" posY="21">
    <Transition to="Display Form"/>
  </Step>
  <Step icon="Approval" name="Display Form" posX="427" posY="21">
    <Approval mode="serial" name="Display Form" owner="ref:launcher" return="buttonActionNext,buttonActionCancel,email,firstName,lastName,mobileNumber,username">
	<AfterScript>
        <Source>
			import sailpoint.object.EmailOptions;
			import sailpoint.object.EmailTemplate;
			import sailpoint.object.Identity;
			import sailpoint.object.WorkItem;
			import sailpoint.tools.Util;
			import sailpoint.api.ObjectUtil;
			import java.util.ArrayList;
			import java.util.List;
		  
			try
			{
				if(Util.isNotNullOrEmpty(buttonActionNext))
				{
					workflow.put("email", email);
					workflow.put("firstName", firstName);
					workflow.put("lastName", lastName);
					workflow.put("mobileNumber", mobileNumber);
					workflow.put("username", username);
				}
			}
			catch (Exception e)
			{
				log.error("Exception in AfterScript ::::  "+e);
			}
			
        </Source>
      </AfterScript>
      <Arg name="workItemType" value="Form"/>
      <Arg name="workItemDescription" value="Guest Account Invite"/>
      <Arg name="workItemForm" value="string:Guest Invite"/>
      <Arg name="workItemFormBasePath"/>
    </Approval>
    <Description>
       Display the Service Account form .
    </Description>
    <Transition to="Execute Rule">
		<Script>
			<Source>
				import sailpoint.tools.Util;
				
				if(Util.isNotNullOrEmpty(buttonActionNext))
				{
				return true;
				}
				return false;
			</Source>
		</Script>
	</Transition>
	<Transition to="Stop"/>
  </Step>
  <Step name="Execute Rule" posX="148" posY="10">
    <Script>
      <Source>
	  import sailpoint.object.Rule;
	  import java.util.HashMap;
		try
        {
            HashMap ruleContext = new HashMap();
            ruleContext.put( "context", context );
			ruleContext.put( "log", log );
            ruleContext.put("email",email);
            ruleContext.put("firstName",firstName);
			ruleContext.put("lastName",lastName);
			ruleContext.put("mobileNumber",mobileNumber);
			ruleContext.put("username",username);
            Rule rule = context.getObjectByName( Rule.class, "Sample-Rule" );
            Object o = context.runRule( rule, ruleContext );
        }
        catch (Exception e)
        {
			log.error("Exception while executing Rule:: "+e);
        }
      </Source>
    </Script>
    <Transition to="Stop"/>
  </Step>
  <Step icon="Stop" name="Stop" posX="611" posY="21"/>
</Workflow>

Feel free to reach out in case of any query . Thanks.

Hi @Chathurya , I would like to further enhance my code to set lastApprovalState based on the rule API response is that possible?

I would also like to get workitem details in the rule

Hi @shijingg,

You cannot change the value of lastApprovalState it will be populated with only two values ‘Finished’ when form is submitted and ‘Rejected’ when the user clicks Back in Form.

Hi @Chathurya , thank you for replying. Then would it be possible to get the work item id in the rule? As I would like to pass the value to an email being triggered from the rule.

Hi @shijingg ,

You can append the below sample code to get the work item id to use it in the rule.

 <Field displayName="WorkItem Id" displayOnly="true" name="workitemId" type="string">
            <Attributes>
              <Map>
                <entry key="hidden" value="true"/>
              </Map>
            </Attributes>
            <Script>
              <Source>String workItemName= "";

                if(workItem!=void &amp;&amp; workItem!=null){

                log.error("WorkItem Id : " +  workItem.getId());

                log.error("WorkItem Name : " +  workItem.getName());

                workItemName = workItem.getName();

                }

                return workItemName;</Source>
            </Script>
          </Field>
```

Append this code in Form in Workflow object from debug page and modify the return variable in form in workflow to include the returned variable ‘workItemName’ to use it later in rule.