Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src/main/java/chain/App.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package chain;

import chain.dto.ApprovalRequestDto;
import chain.enums.RequestType;
import chain.handler.ApprovalHandler;
import chain.processor.CEO;
import chain.processor.DepartmentManager;
import chain.processor.HRManager;

public class App {
public static void main(String[] args) {
// Chain:deptManager -> hrManager -> CEO
ApprovalHandler deptManager = new DepartmentManager();
ApprovalHandler hrManager = new HRManager();
ApprovalHandler ceo = new CEO();

deptManager.linkWith(hrManager).linkWith(ceo);

// Different scene requests
ApprovalRequestDto r1 = new ApprovalRequestDto(RequestType.LEAVE, "Alice", 0, 2);
ApprovalRequestDto r2 = new ApprovalRequestDto(RequestType.EXPENSE, "Bob", 800, 0);
ApprovalRequestDto r3 = new ApprovalRequestDto(RequestType.PURCHASE, "Charlie", 5000, 0);
ApprovalRequestDto r4 = new ApprovalRequestDto(RequestType.LEAVE, "David", 0, 10);

System.out.println("--- Start processing requests ---");
System.out.printf("--- r1 start [%s]---%n", r1.getType());
deptManager.handle(r1);
System.out.printf("--- r1 end [%s]---%n", r1.getType());
System.out.printf("--- r2 start [%s]---%n", r2.getType());
deptManager.handle(r2);
System.out.printf("--- r2 end [%s]---%n", r2.getType());
System.out.printf("--- r3 start [%s]---%n", r3.getType());
deptManager.handle(r3);
System.out.printf("--- r3 end [%s]---%n", r3.getType());
System.out.printf("--- r4 start [%s]---%n", r4.getType());
deptManager.handle(r4);
System.out.printf("--- r4 end [%s]---%n", r4.getType());

System.out.println("--- Request processing completed ---");
}
}
14 changes: 14 additions & 0 deletions src/main/java/chain/dto/ApprovalRequestDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package chain.dto;

import chain.enums.RequestType;
import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
@Getter
public class ApprovalRequestDto {
private final RequestType type;
private final String applicant;
private final double amount;
private final int days;
}
38 changes: 38 additions & 0 deletions src/main/java/chain/enums/RequestType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package chain.enums;

public enum RequestType {
LEAVE("Leave Application"),
EXPENSE("Expense Reimbursement "),
PURCHASE("Procurement Request"),
;

private final String typeName;

RequestType(String typeName) {
this.typeName = typeName;
}

/**
* Get a description of the type
* @return description of the type
*/
public String getType() {
return typeName;
}

/**
* Search for the corresponding enumeration value based on the string (case-insensitive)
* @param typeStr Type string
* @return Corresponding enumeration values
* @throws IllegalArgumentException If no matching enumeration value can be found
*/
public static RequestType fromString(String typeStr) {
for (RequestType type : values()) {
if (type.typeName.equalsIgnoreCase(typeStr)
|| type.name().equalsIgnoreCase(typeStr)) {
return type;
}
}
throw new IllegalArgumentException("Invalid request type: " + typeStr);
}
}
41 changes: 41 additions & 0 deletions src/main/java/chain/handler/ApprovalHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package chain.handler;

import chain.dto.ApprovalRequestDto;
import chain.service.ApprovalRuleService;

import java.util.List;

public abstract class ApprovalHandler {
protected ApprovalHandler next;
private final List<ApprovalRuleService> rules;

public ApprovalHandler(List<ApprovalRuleService> rules) {
this.rules = rules;
}

//pipeline
public ApprovalHandler linkWith(ApprovalHandler next) {
this.next = next;
return next;
}

public void handle(ApprovalRequestDto request) {
if (rules.stream().anyMatch(rule -> rule.evaluate(request))) {
System.out.printf("[%s]Approve the %s application for %s: days=%d, amount=%.2f%n",
getClass().getSimpleName(), request.getApplicant(), request.getType(),
request.getDays(), request.getAmount());
} else {
System.out.printf("[%s]Not in compliance with approval rules, transferred to the next level: %s%n",
getClass().getSimpleName(), next != null ? next.getClass().getSimpleName() : "Null");
passToNext(request);
}
}

protected void passToNext(ApprovalRequestDto request) {
if (next != null) {
next.handle(request);
} else {
System.out.println("[SYSTEM] No one can process this request: " + request.getType());
}
}
}
12 changes: 12 additions & 0 deletions src/main/java/chain/processor/CEO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package chain.processor;

import chain.handler.ApprovalHandler;
import chain.service.impl.DefaultRuleService;

import java.util.List;

public class CEO extends ApprovalHandler {
public CEO() {
super(List.of(new DefaultRuleService()));
}
}
12 changes: 12 additions & 0 deletions src/main/java/chain/processor/DepartmentManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package chain.processor;

import chain.handler.ApprovalHandler;
import chain.service.impl.LeaveDaysRuleService;

import java.util.List;

public class DepartmentManager extends ApprovalHandler {
public DepartmentManager() {
super(List.of(new LeaveDaysRuleService(3)));
}
}
16 changes: 16 additions & 0 deletions src/main/java/chain/processor/HRManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package chain.processor;

import chain.handler.ApprovalHandler;
import chain.service.impl.ExpenseAmountRuleService;
import chain.service.impl.LeaveDaysRuleService;

import java.util.Arrays;

public class HRManager extends ApprovalHandler {
public HRManager() {
super(Arrays.asList(
new LeaveDaysRuleService(7),
new ExpenseAmountRuleService(1000)
));
}
}
9 changes: 9 additions & 0 deletions src/main/java/chain/service/ApprovalRuleService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package chain.service;

import chain.dto.ApprovalRequestDto;

public interface ApprovalRuleService {
boolean evaluate(ApprovalRequestDto request);

String getName();
}
16 changes: 16 additions & 0 deletions src/main/java/chain/service/impl/DefaultRuleService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package chain.service.impl;

import chain.dto.ApprovalRequestDto;
import chain.service.ApprovalRuleService;

public class DefaultRuleService implements ApprovalRuleService {
@Override
public boolean evaluate(ApprovalRequestDto request) {
return true;
}

@Override
public String getName() {
return "True";
}
}
23 changes: 23 additions & 0 deletions src/main/java/chain/service/impl/ExpenseAmountRuleService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package chain.service.impl;

import chain.dto.ApprovalRequestDto;
import chain.enums.RequestType;
import chain.service.ApprovalRuleService;

public class ExpenseAmountRuleService implements ApprovalRuleService {
private final double maxAmount;

public ExpenseAmountRuleService(double maxAmount) {
this.maxAmount = maxAmount;
}

@Override
public boolean evaluate(ApprovalRequestDto req) {
return req.getType() == RequestType.EXPENSE && req.getAmount() <= maxAmount;
}

@Override
public String getName() {
return "Expense<=" + maxAmount;
}
}
23 changes: 23 additions & 0 deletions src/main/java/chain/service/impl/LeaveDaysRuleService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package chain.service.impl;

import chain.dto.ApprovalRequestDto;
import chain.enums.RequestType;
import chain.service.ApprovalRuleService;

public class LeaveDaysRuleService implements ApprovalRuleService {
private final int maxDays;

public LeaveDaysRuleService(int maxDays) {
this.maxDays = maxDays;
}

@Override
public boolean evaluate(ApprovalRequestDto req) {
return req.getType() == RequestType.LEAVE && req.getDays() <= maxDays;
}

@Override
public String getName() {
return "LeaveDays<=" + maxDays;
}
}
17 changes: 17 additions & 0 deletions src/main/java/chain/service/impl/PurchaseTypeRuleService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package chain.service.impl;

import chain.dto.ApprovalRequestDto;
import chain.enums.RequestType;
import chain.service.ApprovalRuleService;

public class PurchaseTypeRuleService implements ApprovalRuleService {
@Override
public boolean evaluate(ApprovalRequestDto req) {
return req.getType() == RequestType.PURCHASE;
}

@Override
public String getName() {
return "Type==PURCHASE";
}
}