class ProblemService {

    void handleDefectIdChange(long projectId, ProblemDTO problemDto, String oldDefectId) throws BadRequestException {
        final Optional<DefectAdapter> maybeDefectAdapter = defectService.getAdapter(projectId);
        if (!maybeDefectAdapter.isPresent()) {
            return;
        }
        DefectAdapter defectAdapter = maybeDefectAdapter.get();

        final String newDefectId = problemDto.getDefectId();
        if (!Objects.equals(newDefectId, oldDefectId)) {
            if (StringUtils.isEmpty(newDefectId)) {
                // Removed defect assignation
                problemDto.setDefectId(null); // "" => null
                problemDto.setDefectExistence(null); // be sure to remove if it was UNKNOWN (EXISTS has no sense neither)
                // Here, we keep the status and closingDateTime unchanged
            } else {
                // Add defect assignation: is format valid? Fast check
                if (!defectAdapter.isValidId(projectId, newDefectId)) {
                    final String hint = defectAdapter.getIdFormatHint(projectId);
                    final String message = String.format(Messages.RULE_PROBLEM_WITH_WRONG_DEFECT_ID_FORMAT, hint);
                    throw new BadRequestException(message, Entities.PROBLEM, "wrong_defect_id_format");
                }

                // Check existence and current status
                final List<Defect> statuses;
                try {
                    statuses = defectAdapter.getStatuses(projectId, Collections.singletonList(newDefectId));
                } catch (FetchException e) {
                    // Also catch RuntimeException to not impact calling code in case of a faulty DefectAdapter in a custom ARA
                    log.error("Cannot check existence of new defect assignation to problem (defect {})", newDefectId, e);
                    problemDto.setDefectExistence(DefectExistence.UNKNOWN); // For re-indexing when connexion to bug-tracker is back
                    problemDto.setStatus(ProblemStatus.OPEN); // In case defect was closed and removed: it should be acted on
                    problemDto.setClosingDateTime(null); // Not CLOSED anymore (if it was)
                    return;
                }
                if (statuses.isEmpty()) {
                    throw new NotFoundException(Messages.NOT_FOUND_DEFECT, "defect");
                } else {
                    problemDto.setDefectExistence(DefectExistence.EXISTS);
                    problemDto.setStatus(statuses.get(0).getStatus());
                    problemDto.setClosingDateTime(statuses.get(0).getCloseDateTime());
                }
            }
        }
    }

}