Overview
Document approval workflows are essential in enterprise applications where multiple stakeholders need to review and authorize documents before they become official. This tutorial demonstrates how to implement a structured approval system using Java, covernig the complete lifecycle from submission to final authorization.
Workflow Process
The approval system follows a sequential process where each stage requires specific actions from different participants. Below is the breakdown of the workflow:
| Stage | Description | Responsible Party |
|---|---|---|
| 1 | Initialize request with required details | Requester |
| 2 | Submit request for review | System |
| 3 | Evaluate and authorize request | Reviewer |
| 4 | Finalize and record outcome | System |
Implementation
Step 1: Define the Request Entity
The foundation of our approval system begins with a data model that captures all necesary information about the request.
public class ApprovalRequest {
private String requestId;
private String documentContent;
private String submittedBy;
private ApprovalStatus status;
private LocalDateTime submissionDate;
private LocalDateTime approvalDate;
public enum ApprovalStatus {
PENDING,
UNDER_REVIEW,
APPROVED,
REJECTED
}
public ApprovalRequest(String requestId, String documentContent, String submittedBy) {
this.requestId = requestId;
this.documentContent = documentContent;
this.submittedBy = submittedBy;
this.status = ApprovalStatus.PENDING;
this.submissionDate = LocalDateTime.now();
}
// Getters and setters omitted for brevity
}
Step 2: Create the Submission Service
This service handles the initial submission of approval requests and manages the state transitions.
public class SubmissionService {
private Map<String, ApprovalRequest> requestRepository;
public SubmissionService() {
this.requestRepository = new HashMap<>();
}
public ApprovalRequest submitRequest(ApprovalRequest request) {
if (request.getStatus() != ApprovalRequest.ApprovalStatus.PENDING) {
throw new IllegalStateException("Request must be in PENDING state");
}
requestRepository.put(request.getRequestId(), request);
request.setStatus(ApprovalRequest.ApprovalStatus.UNDER_REVIEW);
return request;
}
public ApprovalRequest retrieveRequest(String requestId) {
return requestRepository.get(requestId);
}
}
Step 3: Implement the Reviewer Handler
The reviewer component is responsible for evaluating requests and making approval decisions.
public class ReviewerHandler {
private String reviewerName;
private List<String> approvalComments;
public ReviewerHandler(String reviewerName) {
this.reviewerName = reviewerName;
this.approvalComments = new ArrayList<>();
}
public void evaluateRequest(ApprovalRequest request) {
if (request.getStatus() != ApprovalRequest.ApprovalStatus.UNDER_REVIEW) {
throw new IllegalStateException("Request is not under review");
}
// Review logic would go here
System.out.println("Reviewer " + reviewerName + " is evaluating request: " + request.getRequestId());
}
public void makeDecision(ApprovalRequest request, boolean approved, String comments) {
approvalComments.add(comments);
request.setStatus(approved ?
ApprovalRequest.ApprovalStatus.APPROVED :
ApprovalRequest.ApprovalStatus.REJECTED);
request.setApprovalDate(LocalDateTime.now());
}
}
Step 4: Create the Completion Manager
The final stage involves recording the completion status and notifying relevant parties.
public class CompletionManager {
private final SubmissionService submissionService;
public CompletionManager(SubmissionService submissionService) {
this.submissionService = submissionService;
}
public void finalizeRequest(String requestId) {
ApprovalRequest request = submissionService.retrieveRequest(requestId);
if (request == null) {
throw new IllegalArgumentException("Request not found: " + requestId);
}
if (request.getStatus() != ApprovalRequest.ApprovalStatus.APPROVED &&
request.getStatus() != ApprovalRequest.ApprovalStatus.REJECTED) {
throw new IllegalStateException("Request must be decided before finalization");
}
System.out.println("Request " + requestId + " has been " + request.getStatus());
}
}
Usage Example
The following demonstrates how these components work together in a typical scenario:
public class WorkflowDemo {
public static void main(String[] args) {
// Initialize services
SubmissionService submissionService = new SubmissionService();
CompletionManager completionManager = new CompletionManager(submissionService);
ReviewerHandler reviewer = new ReviewerHandler("John Doe");
// Create and submit request
ApprovalRequest request = new ApprovalRequest(
"REQ-001",
"Contract document for project X",
"Alice Smith"
);
// Submit the request
submissionService.submitRequest(request);
// Reviewer evaluates and approves
reviewer.evaluateRequest(request);
reviewer.makeDecision(request, true, "Document meets all requirements");
// Complete the workflow
completionManager.finalizeRequest("REQ-001");
}
}