Integration with Workflow service
e) Integration with workflow - Integration with workflow service requires the following steps -
i) Add a workflow object to VoterRegistrationApplication
POJO -
@Valid
@JsonProperty("workflow")
private Workflow workflow = null;
Create ProcessInstance
, State
, Action
, ProcessInstanceRequest
, ProcessInstanceResponse
, BusinessService
, BusinessServiceResponse
POJOs -
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@EqualsAndHashCode(of = { "id" })
@ToString
public class ProcessInstance {
@Size(max = 64)
@JsonProperty("id")
private String id;
@NotNull
@Size(max = 128)
@JsonProperty("tenantId")
private String tenantId;
@NotNull
@Size(max = 128)
@JsonProperty("businessService")
private String businessService;
@NotNull
@Size(max = 128)
@JsonProperty("businessId")
private String businessId;
@NotNull
@Size(max = 128)
@JsonProperty("action")
private String action;
@NotNull
@Size(max = 64)
@JsonProperty("moduleName")
private String moduleName;
@JsonProperty("state")
private State state;
@JsonProperty("comment")
private String comment;
@JsonProperty("documents")
@Valid
private List<Document> documents;
@JsonProperty("assignes")
private List<User> assignes;
public ProcessInstance addDocumentsItem(Document documentsItem) {
if (this.documents == null) {
this.documents = new ArrayList<>();
}
if (!this.documents.contains(documentsItem))
this.documents.add(documentsItem);
return this;
}
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ToString
@EqualsAndHashCode(of = {"tenantId","businessServiceId","state"})
public class State {
@Size(max=256)
@JsonProperty("uuid")
private String uuid;
@Size(max=256)
@JsonProperty("tenantId")
private String tenantId;
@Size(max=256)
@JsonProperty("businessServiceId")
private String businessServiceId;
@JsonProperty("sla")
private Long sla;
@Size(max=256)
@JsonProperty("state")
private String state;
@Size(max=256)
@JsonProperty("applicationStatus")
private String applicationStatus;
@JsonProperty("docUploadRequired")
private Boolean docUploadRequired;
@JsonProperty("isStartState")
private Boolean isStartState;
@JsonProperty("isTerminateState")
private Boolean isTerminateState;
@JsonProperty("isStateUpdatable")
private Boolean isStateUpdatable;
@JsonProperty("actions")
@Valid
private List<Action> actions;
private AuditDetails auditDetails;
public State addActionsItem(Action actionsItem) {
if (this.actions == null) {
this.actions = new ArrayList<>();
}
this.actions.add(actionsItem);
return this;
}
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ToString
@EqualsAndHashCode(of = {"tenantId","currentState","action"})
public class Action {
@Size(max=256)
@JsonProperty("uuid")
private String uuid;
@Size(max=256)
@JsonProperty("tenantId")
private String tenantId;
@Size(max=256)
@JsonProperty("currentState")
private String currentState;
@Size(max=256)
@JsonProperty("action")
private String action;
@Size(max=256)
@JsonProperty("nextState")
private String nextState;
@Size(max=1024)
@JsonProperty("roles")
@Valid
private List<String> roles;
private AuditDetails auditDetails;
public Action addRolesItem(String rolesItem) {
if (this.roles == null) {
this.roles = new ArrayList<>();
}
this.roles.add(rolesItem);
return this;
}
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ToString
public class ProcessInstanceRequest {
@JsonProperty("RequestInfo")
private RequestInfo requestInfo;
@JsonProperty("ProcessInstances")
@Valid
@NotNull
private List<ProcessInstance> processInstances;
public ProcessInstanceRequest addProcessInstanceItem(ProcessInstance processInstanceItem) {
if (this.processInstances == null) {
this.processInstances = new ArrayList<>();
}
this.processInstances.add(processInstanceItem);
return this;
}
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ProcessInstanceResponse {
@JsonProperty("ResponseInfo")
private ResponseInfo responseInfo;
@JsonProperty("ProcessInstances")
@Valid
private List<ProcessInstance> processInstances;
public ProcessInstanceResponse addProceInstanceItem(ProcessInstance proceInstanceItem) {
if (this.processInstances == null) {
this.processInstances = new ArrayList<>();
}
this.processInstances.add(proceInstanceItem);
return this;
}
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ToString
@EqualsAndHashCode(of = {"tenantId","businessService"})
@JsonInclude(JsonInclude.Include.NON_NULL)
public class BusinessService {
@Size(max=256)
@JsonProperty("tenantId")
private String tenantId = null;
@Size(max=256)
@JsonProperty("uuid")
private String uuid = null;
@Size(max=256)
@JsonProperty("businessService")
private String businessService = null;
@Size(max=256)
@JsonProperty("business")
private String business = null;
@Size(max=1024)
@JsonProperty("getUri")
private String getUri = null;
@Size(max=1024)
@JsonProperty("postUri")
private String postUri = null;
@JsonProperty("businessServiceSla")
private Long businessServiceSla = null;
@NotNull
@Valid
@JsonProperty("states")
private List<State> states = null;
@JsonProperty("auditDetails")
private AuditDetails auditDetails = null;
public BusinessService addStatesItem(State statesItem) {
if (this.states == null) {
this.states = new ArrayList<>();
}
this.states.add(statesItem);
return this;
}
/**
* Returns the currentState with the given uuid if not present returns null
* @param uuid the uuid of the currentState to be returned
* @return
*/
public State getStateFromUuid(String uuid) {
State state = null;
if(this.states!=null){
for(State s : this.states){
if(s.getUuid().equalsIgnoreCase(uuid)){
state = s;
break;
}
}
}
return state;
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString
public class BusinessServiceResponse {
@JsonProperty("ResponseInfo")
private ResponseInfo responseInfo;
@JsonProperty("BusinessServices")
@Valid
@NotNull
private List<BusinessService> businessServices;
public BusinessServiceResponse addBusinessServiceItem(BusinessService businessServiceItem) {
if (this.businessServices == null) {
this.businessServices = new ArrayList<>();
}
this.businessServices.add(businessServiceItem);
return this;
}
}
ii) Next, we have to create a class to transition the workflow object across its states. For this, create a class by the name of WorkflowService
and annotate it with @Service
annotation. Add the following content to this class -
@Component
public class WorkflowService {
@Autowired
private ObjectMapper mapper;
@Autowired
private ServiceRequestRepository repository;
@Autowired
private VTRConfiguration config;
public void updateWorkflowStatus(VoterRegistrationRequest voterRegistrationRequest) {
voterRegistrationRequest.getVoterRegistrationApplications().forEach(application -> {
ProcessInstance processInstance = getProcessInstanceForVTR(application, voterRegistrationRequest.getRequestInfo());
ProcessInstanceRequest workflowRequest = new ProcessInstanceRequest(voterRegistrationRequest.getRequestInfo(), Collections.singletonList(processInstance));
callWorkFlow(workflowRequest);
});
}
public State callWorkFlow(ProcessInstanceRequest workflowReq) {
ProcessInstanceResponse response = null;
StringBuilder url = new StringBuilder(config.getWfHost().concat(config.getWfTransitionPath()));
Object optional = repository.fetchResult(url, workflowReq);
response = mapper.convertValue(optional, ProcessInstanceResponse.class);
return response.getProcessInstances().get(0).getState();
}
private ProcessInstance getProcessInstanceForVTR(VoterRegistrationApplication application, RequestInfo requestInfo) {
Workflow workflow = application.getWorkflow();
ProcessInstance processInstance = new ProcessInstance();
processInstance.setBusinessId(application.getApplicationNumber());
processInstance.setAction(workflow.getAction());
processInstance.setModuleName("voter-services");
processInstance.setTenantId(application.getTenantId());
processInstance.setBusinessService("VTR");
processInstance.setDocuments(workflow.getDocuments());
processInstance.setComment(workflow.getComments());
if(!CollectionUtils.isEmpty(workflow.getAssignes())){
List<User> users = new ArrayList<>();
workflow.getAssignes().forEach(uuid -> {
digit.web.models.User user = new digit.web.models.User();
user.setUuid(uuid);
users.add(user);
});
processInstance.setAssignes(users);
}
return processInstance;
}
private BusinessService getBusinessService(VoterRegistrationApplication application, RequestInfo requestInfo) {
String tenantId = application.getTenantId();
StringBuilder url = getSearchURLWithParams(tenantId, "VTR");
RequestInfoWrapper requestInfoWrapper = RequestInfoWrapper.builder().requestInfo(requestInfo).build();
Object result = repository.fetchResult(url, requestInfoWrapper);
BusinessServiceResponse response = null;
try {
response = mapper.convertValue(result, BusinessServiceResponse.class);
} catch (IllegalArgumentException e) {
throw new CustomException("PARSING ERROR", "Failed to parse response of workflow business service search");
}
if (CollectionUtils.isEmpty(response.getBusinessServices()))
throw new CustomException("BUSINESSSERVICE_NOT_FOUND", "The businessService " + "VTR" + " is not found");
return response.getBusinessServices().get(0);
}
private StringBuilder getSearchURLWithParams(String tenantId, String businessService) {
StringBuilder url = new StringBuilder(config.getWfHost());
url.append(config.getWfBusinessServiceSearchPath());
url.append("?tenantId=");
url.append(tenantId);
url.append("&businessServices=");
url.append(businessService);
return url;
}
public ProcessInstanceRequest getProcessInstanceForVoterRegistrationPayment(VoterRegistrationRequest updateRequest) {
VoterRegistrationApplication application = updateRequest.getVoterRegistrationApplications().get(0);
ProcessInstance process = ProcessInstance.builder()
.businessService("VTR")
.businessId(application.getApplicationNumber())
.comment("Payment for voter registration processed")
.moduleName("voter-services")
.tenantId(application.getTenantId())
.action("PAY")
.build();
return ProcessInstanceRequest.builder()
.requestInfo(updateRequest.getRequestInfo())
.processInstances(Arrays.asList(process))
.build();
}
}
iii) Add the following properties to application.properties file -