Не понимаю как создать ссылку на следующий handler, которые лежать в списке handlers

112
07 февраля 2021, 12:40

У меня учебный проект на Spring MVC и я пытаюсь применить паттерн Chain of responsibility. Создал пакет handler в котором есть интерфейс Handler

public interface Handler {
    void setRelationship(Relationship relationship, User user, String status, Long userIdTo, Long idUserFrom)throws BadRequestException, InternalServerError;
}

Абстрактный класс

public abstract class RelationshipHandler implements Handler, Ordered {
    public abstract void setRelationship(Relationship relationship, User user, String status, Long userIdTo, Long idUserFrom)throws BadRequestException, InternalServerError;
    boolean checkStatusForChange(Relationship relationship, RelationshipStatusType currentStatus, RelationshipStatusType newStatus, String status){
        return relationship != null && relationship.getStatusType().equals(currentStatus) && status.equals(newStatus.toString());
    }
}

От которого наследуются четыре обработчика Первый

@Component
public class AcceptedHandler extends RelationshipHandler {
    private final RelationshipDAO relationshipDAO;
    @Autowired
    public AcceptedHandler(RelationshipDAO relationshipDAO) {
        this.relationshipDAO = relationshipDAO;
    }
    @Override
    public void setRelationship(Relationship relationship, User user, String status, Long idUserTo, Long idUserFrom) throws BadRequestException, InternalServerError{
        if (user != null && user.getId().equals(idUserTo) &&
                checkStatusForChange(relationship, RelationshipStatusType.REQUESTED, RelationshipStatusType.ACCEPTED, status)){
            relationshipDAO.update(addFriendsByRequest(user, relationship));
        }
    }
    private Relationship addFriendsByRequest(User user, Relationship relationship) throws BadRequestException, InternalServerError {
        if (user == null || relationship == null){
            throw new BadRequestException("User or relationship is not found.");
        }
        if (checkingNumberFriends(user.getId())){
            Date acceptedRequest = new Date();
            relationship.setAcceptedFriends(acceptedRequest);
            relationship.setStatusType(RelationshipStatusType.ACCEPTED);
        }
        else {
            throw new BadRequestException("Friends limit exceeded.");
        }
        return relationship;
    }
    private boolean checkingNumberFriends(Long id) throws BadRequestException, InternalServerError {
        if (id == null){
            throw new BadRequestException("ID does not exist.");
        }
        return relationshipDAO.getQuantityFriends(id, RelationshipStatusType.ACCEPTED) < 10;
    }
    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}

Второй

@Component
public class DeletedHandler extends RelationshipHandler {
    private final RelationshipDAO relationshipDAO;
    @Autowired
    public DeletedHandler(RelationshipDAO relationshipDAO) {
        this.relationshipDAO = relationshipDAO;
    }
    @Override
    public void setRelationship(Relationship relationship, User user, String status, Long idUserTo, Long idUserFrom) throws BadRequestException, InternalServerError {
        if (user != null && (user.getId().equals(idUserFrom) || user.getId().equals(idUserTo)) &&
                checkStatusForChange(relationship, RelationshipStatusType.ACCEPTED, RelationshipStatusType.DELETED, status)){
            relationshipDAO.update(delFromFriends(idUserFrom, idUserTo,  relationship));
        }
    }
    private Relationship delFromFriends(Long idUserFrom, Long idUserTo, Relationship relationship) throws BadRequestException, InternalServerError {
        if (idUserFrom == null || idUserTo == null || relationship == null){
            throw new BadRequestException("IdUserFrom or idUserTo or relationship is not found.");
        }
        if (checkingAcceptedDate(idUserFrom, idUserTo)){
            relationship.setStatusType(RelationshipStatusType.DELETED);
            relationship.setAcceptedFriends(null);
        }
        else {
            throw new BadRequestException("You can not perform an action delete from friends.");
        }
        return relationship;
    }
    private boolean checkingAcceptedDate(Long idUserFrom, Long idUserTo) throws BadRequestException, InternalServerError{
        if (idUserFrom == null || idUserTo == null){
            throw new BadRequestException("IdUserFrom or idUserTo is not found.");
        }
        return relationshipDAO.getQuantityHoursAfterAccepted(idUserFrom, idUserTo, RelationshipStatusType.ACCEPTED) >= 3;
    }
    @Override
    public int getOrder() {
        return 2;
    }
}

Третий

@Component
public class CanceledHandler extends RelationshipHandler {
    private final RelationshipDAO relationshipDAO;
    @Autowired
    public CanceledHandler(RelationshipDAO relationshipDAO) {
        this.relationshipDAO = relationshipDAO;
    }
    @Override
    public void setRelationship(Relationship relationship, User user, String status, Long idUserTo, Long idUserFrom) throws BadRequestException, InternalServerError {
        if (user != null && user.getId().equals(idUserFrom) &&
                checkStatusForChange(relationship, RelationshipStatusType.REQUESTED, RelationshipStatusType.CANCELED, status)){
            relationship.setStatusType(RelationshipStatusType.CANCELED);
            relationshipDAO.update(relationship);
        }
    }
    @Override
    public int getOrder() {
        return 3;
    }
}

И четвертый

@Component
public class DeclinedHandler extends RelationshipHandler {
    private final RelationshipDAO relationshipDAO;
    @Autowired
    public DeclinedHandler(RelationshipDAO relationshipDAO) {
        this.relationshipDAO = relationshipDAO;
    }
    @Override
    public void setRelationship(Relationship relationship, User user, String status, Long idUserTo, Long idUserFrom) throws BadRequestException, InternalServerError {
        if (user != null && user.getId().equals(idUserTo) &&
                checkStatusForChange(relationship, RelationshipStatusType.REQUESTED, RelationshipStatusType.DECLINED, status)) {
            relationship.setStatusType(RelationshipStatusType.DECLINED);
            relationshipDAO.update(relationship);
        }
    }
    @Override
    public int getOrder() {
        return 1;
    }
}

Класс в котором строю цепочку

@Component
public class HandlerForUser {
    @Autowired
    private List<Handler> handlers;
    @PostConstruct
    public void init(){
        handlers.sort(INSTANCE);
    }
    public void execute(Relationship relationship, User user, String status, Long idUserTo, Long idUserFrom)throws BadRequestException, InternalServerError {
        for (Handler handler : handlers){
            handler.setRelationship(relationship, user, status, idUserTo, idUserFrom);
        }
    }
}

И использую это в сервисе:

@Service
public class RelationshipService {
    private RelationshipDAO relationshipDAO;
    private UserDAO userDAO;
    private HandlerForUser handlerForUser;
    @Autowired
    public RelationshipService(RelationshipDAO relationshipDAO, UserDAO userDAO, HandlerForUser handlerForUser) {
        this.relationshipDAO = relationshipDAO;
        this.userDAO = userDAO;
        this.handlerForUser = handlerForUser;
    }
    public void setRelationship(String userIdTo, String userIdFrom, HttpSession session)throws BadRequestException, InternalServerError{
        User userFrom = (User) session.getAttribute(userIdFrom);
        if (userFrom == null){
            throw new BadRequestException("User with ID " + userIdFrom + " is not logged in.");
        }
        User userTo = userDAO.findById(Long.parseLong(userIdTo));
        if (userTo == null){
            throw new BadRequestException("User with ID " + userIdTo + " is not found in DB.");
        }
        Relationship relationshipFind = relationshipDAO.getRelationship(userFrom.getId(), userTo.getId());
        try {
            if (relationshipFind == null){
                Relationship relationship = new Relationship();
                relationship.setUserFrom(userFrom);
                relationship.setUserTo(userTo);
                relationship.setStatusType(RelationshipStatusType.REQUESTED);
                save(sendRequest(Long.parseLong(userIdFrom), relationship));
            }
            else if (relationshipFind.getStatusType().equals(RelationshipStatusType.CANCELED) ||
                    relationshipFind.getStatusType().equals(RelationshipStatusType.DECLINED) ||
                    relationshipFind.getStatusType().equals(RelationshipStatusType.DELETED)){
                relationshipFind.setStatusType(RelationshipStatusType.REQUESTED);
                relationshipDAO.update(sendRequest(Long.valueOf(userIdFrom), relationshipFind));
            }
            else {
                throw new BadRequestException("Something is wrong with the input.");
            }
        }catch (InternalServerError e) {
            throw new InternalServerError("Something went wrong...");
        }
    }
    public void setRelationshipByStatus(String status, String userIdTo, String userIdFrom, HttpSession session) throws BadRequestException, InternalServerError {
        if (status == null || userIdTo == null || userIdFrom == null){
            throw  new BadRequestException("Status or userIdTo or userIdFrom is not exist.");
        }
        User userFrom = (User) session.getAttribute(userIdFrom);
        User userTo = (User) session.getAttribute(userIdTo);
        Relationship relationshipFind = relationshipDAO.getRelationship(Long.valueOf(userIdFrom), Long.valueOf(userIdTo));
        try {
            if (userTo != null){
                handlerForUser.execute(relationshipFind, userTo, status, Long.valueOf(userIdTo), Long.valueOf(userIdFrom));
            }
            if (userFrom != null){
                handlerForUser.execute(relationshipFind, userFrom, status, Long.valueOf(userIdTo), Long.valueOf(userIdFrom));
            }
            else {
                throw new BadRequestException("Something is wrong with the input. Method setRelationshipByStatus");
            }
        }catch (InternalServerError e) {
            throw new InternalServerError("Something went wrong...");
        }
    }
    public void validationInputData(String idUserFrom, String idUserTo, HttpSession session)throws BadRequestException{
        if (idUserFrom == null || idUserTo == null){
            throw  new BadRequestException("UserFrom or userTo does not exist.");
        }
        if (idUserFrom.equals(idUserTo)){
            throw  new BadRequestException("Actions between the same user are not possible.");
        }
        if (session == null){
            throw  new BadRequestException("Session is not exist.");
        }
    }
    private Relationship save(Relationship relationship)throws BadRequestException {
        if (relationship != null && relationship.getId() != null){
            throw new BadRequestException("This Relationship with ID - " + relationship.getId() + " can not save in DB.");
        }
        else {
            relationshipDAO.save(relationship);
        }
        return relationship;
    }
    private Relationship sendRequest(Long idUser, Relationship relationship) throws BadRequestException, InternalServerError {
        if (idUser == null || relationship == null){
            throw new BadRequestException("User or relationship is not found.");
        }
        if (checkingNumberRequested(idUser)){
            relationship.setStatusType(RelationshipStatusType.REQUESTED);
        }
        else {
            throw new BadRequestException("Limit on sent requests exceeded.");
        }
        return relationship;
    }
    private boolean checkingNumberRequested(Long id) throws BadRequestException, InternalServerError{
        if (id == null){
            throw new BadRequestException("ID does not exist.");
        }
        return relationshipDAO.getQuantityRequests(id, RelationshipStatusType.REQUESTED) < 10;
    }
}

Сейчас получается, что запрос проходит по всему списку обработчиков не прерывая цепочку если запрос обработался успешно. Может я структуру построил не правильно. Наверное в абстрактном классе надо задать поведение для передачи ссылки на следующий обработчик. Что-то ни как не соображу, что делать дальше... Помогите разобраться, как правильно построить цепочку

Answer 1

Я отказался от использования списка. Реализовал построение цепочки через передачу ссылок от одного обработчика другому. Теперь класс, в котором создается цепочка обязанностей выглядит вот так:

@Component
public class HandlerChain {
    private Handler chain;
    public HandlerChain(RelationshipDAO relationshipDAO){
        this.chain = new AcceptedHandler(relationshipDAO);
        Handler declinedHandlerObj = new DeclinedHandler(relationshipDAO);
        Handler canceledHandlerObj = new CanceledHandler(relationshipDAO);
        Handler deletedHandlerObj = new DeletedHandler(relationshipDAO);
        chain.setNextHandler(declinedHandlerObj);
        declinedHandlerObj.setNextHandler(canceledHandlerObj);
        canceledHandlerObj.setNextHandler(deletedHandlerObj);
    }
    public void execute(Relationship relationship, User user, String status, Long userIdTo, Long idUserFrom)throws BadRequestException, InternalServerError{
        chain.setRelationship(relationship, user, status, userIdTo, idUserFrom);
    }
}
READ ALSO
Типизация объектов

Типизация объектов

У меня есть класс AppealTemlate, который содержит список сущностей extends AbstractFieldВыглядит это примерно так:

120
Как удалить все строки в текстовом файле, начинающиеся с определенного символа?

Как удалить все строки в текстовом файле, начинающиеся с определенного символа?

Как удалить все строки в текстовом файле, начинающиеся с определенного символа?

134