Example usage for org.springframework.dao DataIntegrityViolationException getCause

List of usage examples for org.springframework.dao DataIntegrityViolationException getCause

Introduction

In this page you can find the example usage for org.springframework.dao DataIntegrityViolationException getCause.

Prototype

public synchronized Throwable getCause() 

Source Link

Document

Returns the cause of this throwable or null if the cause is nonexistent or unknown.

Usage

From source file:com.gst.portfolio.client.service.ClientWritePlatformServiceJpaRepositoryImpl.java

@Transactional
@Override/*w  w w  .j  av  a  2s  .c o  m*/
public CommandProcessingResult createClient(final JsonCommand command) {

    try {
        final AppUser currentUser = this.context.authenticatedUser();

        this.fromApiJsonDeserializer.validateForCreate(command.json());

        final GlobalConfigurationPropertyData configuration = this.configurationReadPlatformService
                .retrieveGlobalConfiguration("Enable-Address");

        final Boolean isAddressEnabled = configuration.isEnabled();

        final Long officeId = command.longValueOfParameterNamed(ClientApiConstants.officeIdParamName);

        final Office clientOffice = this.officeRepositoryWrapper.findOneWithNotFoundDetection(officeId);

        final Long groupId = command.longValueOfParameterNamed(ClientApiConstants.groupIdParamName);

        Group clientParentGroup = null;
        if (groupId != null) {
            clientParentGroup = this.groupRepository.findOne(groupId);
            if (clientParentGroup == null) {
                throw new GroupNotFoundException(groupId);
            }
        }

        Staff staff = null;
        final Long staffId = command.longValueOfParameterNamed(ClientApiConstants.staffIdParamName);
        if (staffId != null) {
            staff = this.staffRepository.findByOfficeHierarchyWithNotFoundDetection(staffId,
                    clientOffice.getHierarchy());
        }

        CodeValue gender = null;
        final Long genderId = command.longValueOfParameterNamed(ClientApiConstants.genderIdParamName);
        if (genderId != null) {
            gender = this.codeValueRepository
                    .findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.GENDER, genderId);
        }

        CodeValue clientType = null;
        final Long clientTypeId = command.longValueOfParameterNamed(ClientApiConstants.clientTypeIdParamName);
        if (clientTypeId != null) {
            clientType = this.codeValueRepository
                    .findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.CLIENT_TYPE, clientTypeId);
        }

        CodeValue clientClassification = null;
        final Long clientClassificationId = command
                .longValueOfParameterNamed(ClientApiConstants.clientClassificationIdParamName);
        if (clientClassificationId != null) {
            clientClassification = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(
                    ClientApiConstants.CLIENT_CLASSIFICATION, clientClassificationId);
        }

        final Long savingsProductId = command
                .longValueOfParameterNamed(ClientApiConstants.savingsProductIdParamName);
        if (savingsProductId != null) {
            SavingsProduct savingsProduct = this.savingsProductRepository.findOne(savingsProductId);
            if (savingsProduct == null) {
                throw new SavingsProductNotFoundException(savingsProductId);
            }
        }

        final Integer legalFormParamValue = command
                .integerValueOfParameterNamed(ClientApiConstants.legalFormIdParamName);
        boolean isEntity = false;
        Integer legalFormValue = null;
        if (legalFormParamValue != null) {
            LegalForm legalForm = LegalForm.fromInt(legalFormParamValue);
            if (legalForm != null) {
                legalFormValue = legalForm.getValue();
                isEntity = legalForm.isEntity();
            }
        }

        final Client newClient = Client.createNew(currentUser, clientOffice, clientParentGroup, staff,
                savingsProductId, gender, clientType, clientClassification, legalFormValue, command);
        this.clientRepository.save(newClient);
        boolean rollbackTransaction = false;
        if (newClient.isActive()) {
            validateParentGroupRulesBeforeClientActivation(newClient);
            runEntityDatatableCheck(newClient.getId());
            final CommandWrapper commandWrapper = new CommandWrapperBuilder().activateClient(null).build();
            rollbackTransaction = this.commandProcessingService.validateCommand(commandWrapper, currentUser);
        }

        this.clientRepository.save(newClient);
        if (newClient.isActive()) {
            this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.CLIENTS_ACTIVATE,
                    constructEntityMap(BUSINESS_ENTITY.CLIENT, newClient));
        }
        if (newClient.isAccountNumberRequiresAutoGeneration()) {
            AccountNumberFormat accountNumberFormat = this.accountNumberFormatRepository
                    .findByAccountType(EntityAccountType.CLIENT);
            newClient.updateAccountNo(accountNumberGenerator.generate(newClient, accountNumberFormat));
            this.clientRepository.save(newClient);
        }

        final Locale locale = command.extractLocale();
        final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
        CommandProcessingResult result = openSavingsAccount(newClient, fmt);
        if (result.getSavingsId() != null) {
            this.clientRepository.save(newClient);

        }

        if (isEntity) {
            extractAndCreateClientNonPerson(newClient, command);
        }

        if (isAddressEnabled) {
            this.addressWritePlatformService.addNewClientAddress(newClient, command);
        }

        if (command.parameterExists(ClientApiConstants.datatables)) {
            this.entityDatatableChecksWritePlatformService.saveDatatables(
                    StatusEnum.CREATE.getCode().longValue(), EntityTables.CLIENT.getName(), newClient.getId(),
                    null, command.arrayOfParameterNamed(ClientApiConstants.datatables));
        }

        this.entityDatatableChecksWritePlatformService.runTheCheck(newClient.getId(),
                EntityTables.CLIENT.getName(), StatusEnum.CREATE.getCode().longValue(),
                EntityTables.CLIENT.getForeignKeyColumnNameOnDatatable());

        return new CommandProcessingResultBuilder() //
                .withCommandId(command.commandId()) //
                .withOfficeId(clientOffice.getId()) //
                .withClientId(newClient.getId()) //
                .withGroupId(groupId) //
                .withEntityId(newClient.getId()) //
                .withSavingsId(result.getSavingsId())//
                .setRollbackTransaction(rollbackTransaction)//
                .setRollbackTransaction(result.isRollbackTransaction())//
                .build();
    } catch (final DataIntegrityViolationException dve) {
        handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
        return CommandProcessingResult.empty();
    } catch (final PersistenceException dve) {
        Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
        handleDataIntegrityIssues(command, throwable, dve);
        return CommandProcessingResult.empty();
    }
}

From source file:com.gst.portfolio.group.service.GroupingTypesWritePlatformServiceJpaRepositoryImpl.java

private CommandProcessingResult updateGroupingType(final Long groupId, final JsonCommand command,
        final GroupTypes groupingType) {

    try {//from   w  w  w .j  a v  a  2s. c  o m
        this.context.authenticatedUser();
        final Group groupForUpdate = this.groupRepository.findOneWithNotFoundDetection(groupId);
        final Long officeId = groupForUpdate.officeId();
        final Office groupOffice = groupForUpdate.getOffice();
        final String groupHierarchy = groupOffice.getHierarchy();

        this.context.validateAccessRights(groupHierarchy);

        final LocalDate activationDate = command
                .localDateValueOfParameterNamed(GroupingTypesApiConstants.activationDateParamName);

        validateOfficeOpeningDateisAfterGroupOrCenterOpeningDate(groupOffice, groupForUpdate.getGroupLevel(),
                activationDate);

        final Map<String, Object> actualChanges = groupForUpdate.update(command);

        if (actualChanges.containsKey(GroupingTypesApiConstants.staffIdParamName)) {
            final Long newValue = command.longValueOfParameterNamed(GroupingTypesApiConstants.staffIdParamName);

            Staff newStaff = null;
            if (newValue != null) {
                newStaff = this.staffRepository.findByOfficeHierarchyWithNotFoundDetection(newValue,
                        groupHierarchy);
            }
            groupForUpdate.updateStaff(newStaff);
        }

        final GroupLevel groupLevel = this.groupLevelRepository.findOne(groupForUpdate.getGroupLevel().getId());

        /*
         * Ignoring parentId param, if group for update is super parent.
         * TODO Need to check: Ignoring is correct or need throw unsupported
         * param
         */
        if (!groupLevel.isSuperParent()) {

            Long parentId = null;
            final Group presentParentGroup = groupForUpdate.getParent();

            if (presentParentGroup != null) {
                parentId = presentParentGroup.getId();
            }

            if (command.isChangeInLongParameterNamed(GroupingTypesApiConstants.centerIdParamName, parentId)) {

                final Long newValue = command
                        .longValueOfParameterNamed(GroupingTypesApiConstants.centerIdParamName);
                actualChanges.put(GroupingTypesApiConstants.centerIdParamName, newValue);
                Group newParentGroup = null;
                if (newValue != null) {
                    newParentGroup = this.groupRepository.findOneWithNotFoundDetection(newValue);

                    if (!newParentGroup.isOfficeIdentifiedBy(officeId)) {
                        final String errorMessage = "Group and parent group must have the same office";
                        throw new InvalidOfficeException("group", "attach.to.parent.group", errorMessage);
                    }
                    /*
                     * If Group is not super parent then validate group
                     * level's parent level is same as group parent's level
                     * this check makes sure new group is added at immediate
                     * next level in hierarchy
                     */

                    if (!groupForUpdate.getGroupLevel()
                            .isIdentifiedByParentId(newParentGroup.getGroupLevel().getId())) {
                        final String errorMessage = "Parent group's level is  not equal to child level's parent level ";
                        throw new InvalidGroupLevelException("add", "invalid.level", errorMessage);
                    }
                }

                groupForUpdate.setParent(newParentGroup);

                // Parent has changed, re-generate 'Hierarchy' as parent is
                // changed
                groupForUpdate.generateHierarchy();

            }
        }

        /*
         * final Set<Client> clientMembers = assembleSetOfClients(officeId,
         * command); List<String> changes =
         * groupForUpdate.updateClientMembersIfDifferent(clientMembers); if
         * (!changes.isEmpty()) {
         * actualChanges.put(GroupingTypesApiConstants
         * .clientMembersParamName, changes); }
         */

        this.groupRepository.saveAndFlush(groupForUpdate);

        return new CommandProcessingResultBuilder() //
                .withCommandId(command.commandId()) //
                .withOfficeId(groupForUpdate.officeId()) //
                .withGroupId(groupForUpdate.getId()) //
                .withEntityId(groupForUpdate.getId()) //
                .with(actualChanges) //
                .build();

    } catch (final DataIntegrityViolationException dve) {
        handleGroupDataIntegrityIssues(command, dve.getMostSpecificCause(), dve, groupingType);
        return CommandProcessingResult.empty();
    } catch (final PersistenceException dve) {
        Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
        handleGroupDataIntegrityIssues(command, throwable, dve, groupingType);
        return CommandProcessingResult.empty();
    }
}

From source file:com.gst.portfolio.client.service.ClientWritePlatformServiceJpaRepositoryImpl.java

@Transactional
@Override//from ww w  . java  2 s  .c o m
public CommandProcessingResult updateClient(final Long clientId, final JsonCommand command) {

    try {
        this.fromApiJsonDeserializer.validateForUpdate(command.json());

        final Client clientForUpdate = this.clientRepository.findOneWithNotFoundDetection(clientId);
        final String clientHierarchy = clientForUpdate.getOffice().getHierarchy();

        this.context.validateAccessRights(clientHierarchy);

        final Map<String, Object> changes = clientForUpdate.update(command);

        if (changes.containsKey(ClientApiConstants.staffIdParamName)) {

            final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.staffIdParamName);
            Staff newStaff = null;
            if (newValue != null) {
                newStaff = this.staffRepository.findByOfficeHierarchyWithNotFoundDetection(newValue,
                        clientForUpdate.getOffice().getHierarchy());
            }
            clientForUpdate.updateStaff(newStaff);
        }

        if (changes.containsKey(ClientApiConstants.genderIdParamName)) {

            final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.genderIdParamName);
            CodeValue gender = null;
            if (newValue != null) {
                gender = this.codeValueRepository
                        .findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.GENDER, newValue);
            }
            clientForUpdate.updateGender(gender);
        }

        if (changes.containsKey(ClientApiConstants.savingsProductIdParamName)) {
            if (clientForUpdate.isActive()) {
                throw new ClientActiveForUpdateException(clientId,
                        ClientApiConstants.savingsProductIdParamName);
            }
            SavingsProduct savingsProduct = null;
            final Long savingsProductId = command
                    .longValueOfParameterNamed(ClientApiConstants.savingsProductIdParamName);
            if (savingsProductId != null) {
                savingsProduct = this.savingsProductRepository.findOne(savingsProductId);
                if (savingsProduct == null) {
                    throw new SavingsProductNotFoundException(savingsProductId);
                }
            }
            clientForUpdate.updateSavingsProduct(savingsProductId);
        }

        if (changes.containsKey(ClientApiConstants.genderIdParamName)) {
            final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.genderIdParamName);
            CodeValue newCodeVal = null;
            if (newValue != null) {
                newCodeVal = this.codeValueRepository
                        .findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.GENDER, newValue);
            }
            clientForUpdate.updateGender(newCodeVal);
        }

        if (changes.containsKey(ClientApiConstants.clientTypeIdParamName)) {
            final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.clientTypeIdParamName);
            CodeValue newCodeVal = null;
            if (newValue != null) {
                newCodeVal = this.codeValueRepository
                        .findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.CLIENT_TYPE, newValue);
            }
            clientForUpdate.updateClientType(newCodeVal);
        }

        if (changes.containsKey(ClientApiConstants.clientClassificationIdParamName)) {
            final Long newValue = command
                    .longValueOfParameterNamed(ClientApiConstants.clientClassificationIdParamName);
            CodeValue newCodeVal = null;
            if (newValue != null) {
                newCodeVal = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(
                        ClientApiConstants.CLIENT_CLASSIFICATION, newValue);
            }
            clientForUpdate.updateClientClassification(newCodeVal);
        }

        if (!changes.isEmpty()) {
            this.clientRepository.saveAndFlush(clientForUpdate);
        }

        if (changes.containsKey(ClientApiConstants.legalFormIdParamName)) {
            Integer legalFormValue = clientForUpdate.getLegalForm();
            boolean isChangedToEntity = false;
            if (legalFormValue != null) {
                LegalForm legalForm = LegalForm.fromInt(legalFormValue);
                if (legalForm != null)
                    isChangedToEntity = legalForm.isEntity();
            }

            if (isChangedToEntity) {
                extractAndCreateClientNonPerson(clientForUpdate, command);
            } else {
                final ClientNonPerson clientNonPerson = this.clientNonPersonRepository
                        .findOneByClientId(clientForUpdate.getId());
                if (clientNonPerson != null)
                    this.clientNonPersonRepository.delete(clientNonPerson);
            }
        }

        final ClientNonPerson clientNonPersonForUpdate = this.clientNonPersonRepository
                .findOneByClientId(clientId);
        if (clientNonPersonForUpdate != null) {
            final JsonElement clientNonPersonElement = this.fromApiJsonHelper
                    .parse(command.jsonFragment(ClientApiConstants.clientNonPersonDetailsParamName));
            final Map<String, Object> clientNonPersonChanges = clientNonPersonForUpdate
                    .update(JsonCommand.fromExistingCommand(command, clientNonPersonElement));

            if (clientNonPersonChanges.containsKey(ClientApiConstants.constitutionIdParamName)) {

                final Long newValue = this.fromApiJsonHelper
                        .extractLongNamed(ClientApiConstants.constitutionIdParamName, clientNonPersonElement);
                CodeValue constitution = null;
                if (newValue != null) {
                    constitution = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(
                            ClientApiConstants.CLIENT_NON_PERSON_CONSTITUTION, newValue);
                }
                clientNonPersonForUpdate.updateConstitution(constitution);
            }

            if (clientNonPersonChanges.containsKey(ClientApiConstants.mainBusinessLineIdParamName)) {

                final Long newValue = this.fromApiJsonHelper.extractLongNamed(
                        ClientApiConstants.mainBusinessLineIdParamName, clientNonPersonElement);
                CodeValue mainBusinessLine = null;
                if (newValue != null) {
                    mainBusinessLine = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(
                            ClientApiConstants.CLIENT_NON_PERSON_MAIN_BUSINESS_LINE, newValue);
                }
                clientNonPersonForUpdate.updateMainBusinessLine(mainBusinessLine);
            }

            if (!clientNonPersonChanges.isEmpty()) {
                this.clientNonPersonRepository.saveAndFlush(clientNonPersonForUpdate);
            }

            changes.putAll(clientNonPersonChanges);
        }

        return new CommandProcessingResultBuilder() //
                .withCommandId(command.commandId()) //
                .withOfficeId(clientForUpdate.officeId()) //
                .withClientId(clientId) //
                .withEntityId(clientId) //
                .with(changes) //
                .build();
    } catch (final DataIntegrityViolationException dve) {
        handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
        return CommandProcessingResult.empty();
    } catch (final PersistenceException dve) {
        Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
        handleDataIntegrityIssues(command, throwable, dve);
        return CommandProcessingResult.empty();
    }
}

From source file:com.gst.portfolio.group.service.GroupingTypesWritePlatformServiceJpaRepositoryImpl.java

private CommandProcessingResult createGroupingType(final JsonCommand command, final GroupTypes groupingType,
        final Long centerId) {
    try {//from   www .  ja v a 2s.  c  om
        final String accountNo = command
                .stringValueOfParameterNamed(GroupingTypesApiConstants.accountNoParamName);
        final String name = command.stringValueOfParameterNamed(GroupingTypesApiConstants.nameParamName);
        final String externalId = command
                .stringValueOfParameterNamed(GroupingTypesApiConstants.externalIdParamName);

        final AppUser currentUser = this.context.authenticatedUser();
        Long officeId = null;
        Group parentGroup = null;

        if (centerId == null) {
            officeId = command.longValueOfParameterNamed(GroupingTypesApiConstants.officeIdParamName);
        } else {
            parentGroup = this.groupRepository.findOneWithNotFoundDetection(centerId);
            officeId = parentGroup.officeId();
        }

        final Office groupOffice = this.officeRepositoryWrapper.findOneWithNotFoundDetection(officeId);

        final LocalDate activationDate = command
                .localDateValueOfParameterNamed(GroupingTypesApiConstants.activationDateParamName);
        final GroupLevel groupLevel = this.groupLevelRepository.findOne(groupingType.getId());

        validateOfficeOpeningDateisAfterGroupOrCenterOpeningDate(groupOffice, groupLevel, activationDate);

        Staff staff = null;
        final Long staffId = command.longValueOfParameterNamed(GroupingTypesApiConstants.staffIdParamName);
        if (staffId != null) {
            staff = this.staffRepository.findByOfficeHierarchyWithNotFoundDetection(staffId,
                    groupOffice.getHierarchy());
        }

        final Set<Client> clientMembers = assembleSetOfClients(officeId, command);

        final Set<Group> groupMembers = assembleSetOfChildGroups(officeId, command);

        final boolean active = command
                .booleanPrimitiveValueOfParameterNamed(GroupingTypesApiConstants.activeParamName);
        LocalDate submittedOnDate = new LocalDate();
        if (active && submittedOnDate.isAfter(activationDate)) {
            submittedOnDate = activationDate;
        }
        if (command.hasParameter(GroupingTypesApiConstants.submittedOnDateParamName)) {
            submittedOnDate = command
                    .localDateValueOfParameterNamed(GroupingTypesApiConstants.submittedOnDateParamName);
        }

        final Group newGroup = Group.newGroup(groupOffice, staff, parentGroup, groupLevel, name, externalId,
                active, activationDate, clientMembers, groupMembers, submittedOnDate, currentUser, accountNo);

        boolean rollbackTransaction = false;
        if (newGroup.isActive()) {
            this.groupRepository.save(newGroup);
            // validate Group creation rules for Group
            if (newGroup.isGroup()) {
                validateGroupRulesBeforeActivation(newGroup);
            }

            if (newGroup.isCenter()) {
                final CommandWrapper commandWrapper = new CommandWrapperBuilder().activateCenter(null).build();
                rollbackTransaction = this.commandProcessingService.validateCommand(commandWrapper,
                        currentUser);
            } else {
                final CommandWrapper commandWrapper = new CommandWrapperBuilder().activateGroup(null).build();
                rollbackTransaction = this.commandProcessingService.validateCommand(commandWrapper,
                        currentUser);
            }
        }

        if (!newGroup.isCenter() && newGroup.hasActiveClients()) {
            final CommandWrapper commandWrapper = new CommandWrapperBuilder()
                    .associateClientsToGroup(newGroup.getId()).build();
            rollbackTransaction = this.commandProcessingService.validateCommand(commandWrapper, currentUser);
        }

        // pre-save to generate id for use in group hierarchy
        this.groupRepository.save(newGroup);

        /*
         * Generate hierarchy for a new center/group and all the child
         * groups if they exist
         */
        newGroup.generateHierarchy();

        /* Generate account number if required */
        generateAccountNumberIfRequired(newGroup);

        this.groupRepository.saveAndFlush(newGroup);
        newGroup.captureStaffHistoryDuringCenterCreation(staff, activationDate);

        if (newGroup.isGroup()) {
            if (command.parameterExists(GroupingTypesApiConstants.datatables)) {
                this.entityDatatableChecksWritePlatformService.saveDatatables(
                        StatusEnum.CREATE.getCode().longValue(), EntityTables.GROUP.getName(), newGroup.getId(),
                        null, command.arrayOfParameterNamed(GroupingTypesApiConstants.datatables));
            }

            this.entityDatatableChecksWritePlatformService.runTheCheck(newGroup.getId(),
                    EntityTables.GROUP.getName(), StatusEnum.CREATE.getCode().longValue(),
                    EntityTables.GROUP.getForeignKeyColumnNameOnDatatable());
        }

        return new CommandProcessingResultBuilder() //
                .withCommandId(command.commandId()) //
                .withOfficeId(groupOffice.getId()) //
                .withGroupId(newGroup.getId()) //
                .withEntityId(newGroup.getId()) //
                .setRollbackTransaction(rollbackTransaction)//
                .build();

    } catch (final DataIntegrityViolationException dve) {
        handleGroupDataIntegrityIssues(command, dve.getMostSpecificCause(), dve, groupingType);
        return CommandProcessingResult.empty();
    } catch (final PersistenceException dve) {
        Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
        handleGroupDataIntegrityIssues(command, throwable, dve, groupingType);
        return CommandProcessingResult.empty();
    }
}

From source file:com.gst.portfolio.loanaccount.service.LoanApplicationWritePlatformServiceJpaRepositoryImpl.java

private void saveAndFlushLoanWithDataIntegrityViolationChecks(final Loan loan) {
    try {/*from  w  w w .  j a  va2s  .  c om*/
        List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
        for (LoanRepaymentScheduleInstallment installment : installments) {
            if (installment.getId() == null) {
                this.repaymentScheduleInstallmentRepository.save(installment);
            }
        }
        this.loanRepositoryWrapper.saveAndFlush(loan);
    } catch (final DataIntegrityViolationException e) {
        final Throwable realCause = e.getCause();
        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
                .resource("loan.application");
        if (realCause.getMessage().toLowerCase().contains("external_id_unique")) {
            baseDataValidator.reset().parameter("externalId").failWithCode("value.must.be.unique");
        }
        if (!dataValidationErrors.isEmpty()) {
            throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
                    "Validation errors exist.", dataValidationErrors);
        }
    }
}

From source file:com.gst.portfolio.loanaccount.service.LoanApplicationWritePlatformServiceJpaRepositoryImpl.java

@Transactional
@Override//from www.ja v a  2  s  .com
public CommandProcessingResult submitApplication(final JsonCommand command) {

    try {
        final AppUser currentUser = getAppUserIfPresent();
        boolean isMeetingMandatoryForJLGLoans = configurationDomainService.isMeetingMandatoryForJLGLoans();
        final Long productId = this.fromJsonHelper.extractLongNamed("productId", command.parsedJson());
        final LoanProduct loanProduct = this.loanProductRepository.findOne(productId);
        if (loanProduct == null) {
            throw new LoanProductNotFoundException(productId);
        }

        final Long clientId = this.fromJsonHelper.extractLongNamed("clientId", command.parsedJson());
        if (clientId != null) {
            Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
            officeSpecificLoanProductValidation(productId, client.getOffice().getId());
        }
        final Long groupId = this.fromJsonHelper.extractLongNamed("groupId", command.parsedJson());
        if (groupId != null) {
            Group group = this.groupRepository.findOneWithNotFoundDetection(groupId);
            officeSpecificLoanProductValidation(productId, group.getOffice().getId());
        }

        this.fromApiJsonDeserializer.validateForCreate(command.json(), isMeetingMandatoryForJLGLoans,
                loanProduct);

        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
                .resource("loan");

        if (loanProduct.useBorrowerCycle()) {
            Integer cycleNumber = 0;
            if (clientId != null) {
                cycleNumber = this.loanReadPlatformService.retriveLoanCounter(clientId, loanProduct.getId());
            } else if (groupId != null) {
                cycleNumber = this.loanReadPlatformService.retriveLoanCounter(groupId,
                        AccountType.GROUP.getValue(), loanProduct.getId());
            }
            this.loanProductCommandFromApiJsonDeserializer.validateMinMaxConstraints(command.parsedJson(),
                    baseDataValidator, loanProduct, cycleNumber);
        } else {
            this.loanProductCommandFromApiJsonDeserializer.validateMinMaxConstraints(command.parsedJson(),
                    baseDataValidator, loanProduct);
        }
        if (!dataValidationErrors.isEmpty()) {
            throw new PlatformApiDataValidationException(dataValidationErrors);
        }

        final Loan newLoanApplication = this.loanAssembler.assembleFrom(command, currentUser);

        validateSubmittedOnDate(newLoanApplication);

        final LoanProductRelatedDetail productRelatedDetail = newLoanApplication.repaymentScheduleDetail();

        if (loanProduct.getLoanProductConfigurableAttributes() != null) {
            updateProductRelatedDetails(productRelatedDetail, newLoanApplication);
        }

        this.fromApiJsonDeserializer.validateLoanTermAndRepaidEveryValues(newLoanApplication.getTermFrequency(),
                newLoanApplication.getTermPeriodFrequencyType(), productRelatedDetail.getNumberOfRepayments(),
                productRelatedDetail.getRepayEvery(),
                productRelatedDetail.getRepaymentPeriodFrequencyType().getValue(), newLoanApplication);

        if (loanProduct.canUseForTopup() && clientId != null) {
            final Boolean isTopup = command.booleanObjectValueOfParameterNamed(LoanApiConstants.isTopup);
            if (null == isTopup) {
                newLoanApplication.setIsTopup(false);
            } else {
                newLoanApplication.setIsTopup(isTopup);
            }

            if (newLoanApplication.isTopup()) {
                final Long loanIdToClose = command.longValueOfParameterNamed(LoanApiConstants.loanIdToClose);
                final Loan loanToClose = this.loanRepositoryWrapper
                        .findNonClosedLoanThatBelongsToClient(loanIdToClose, clientId);
                if (loanToClose == null) {
                    throw new GeneralPlatformDomainRuleException(
                            "error.msg.loan.loanIdToClose.no.active.loan.associated.to.client.found",
                            "loanIdToClose is invalid, No Active Loan associated with the given Client ID found.");
                }
                if (loanToClose.isMultiDisburmentLoan()
                        && !loanToClose.isInterestRecalculationEnabledForProduct()) {
                    throw new GeneralPlatformDomainRuleException(
                            "error.msg.loan.topup.on.multi.tranche.loan.without.interest.recalculation.not.supported",
                            "Topup on loan with multi-tranche disbursal and without interest recalculation is not supported.");
                }
                final LocalDate disbursalDateOfLoanToClose = loanToClose.getDisbursementDate();
                if (!newLoanApplication.getSubmittedOnDate().isAfter(disbursalDateOfLoanToClose)) {
                    throw new GeneralPlatformDomainRuleException(
                            "error.msg.loan.submitted.date.should.be.after.topup.loan.disbursal.date",
                            "Submitted date of this loan application " + newLoanApplication.getSubmittedOnDate()
                                    + " should be after the disbursed date of loan to be closed "
                                    + disbursalDateOfLoanToClose);
                }
                if (!loanToClose.getCurrencyCode().equals(newLoanApplication.getCurrencyCode())) {
                    throw new GeneralPlatformDomainRuleException(
                            "error.msg.loan.to.be.closed.has.different.currency",
                            "loanIdToClose is invalid, Currency code is different.");
                }
                final LocalDate lastUserTransactionOnLoanToClose = loanToClose.getLastUserTransactionDate();
                if (!newLoanApplication.getDisbursementDate().isAfter(lastUserTransactionOnLoanToClose)) {
                    throw new GeneralPlatformDomainRuleException(
                            "error.msg.loan.disbursal.date.should.be.after.last.transaction.date.of.loan.to.be.closed",
                            "Disbursal date of this loan application "
                                    + newLoanApplication.getDisbursementDate()
                                    + " should be after last transaction date of loan to be closed "
                                    + lastUserTransactionOnLoanToClose);
                }
                BigDecimal loanOutstanding = this.loanReadPlatformService
                        .retrieveLoanPrePaymentTemplate(loanIdToClose, newLoanApplication.getDisbursementDate())
                        .getAmount();
                final BigDecimal firstDisbursalAmount = newLoanApplication.getFirstDisbursalAmount();
                if (loanOutstanding.compareTo(firstDisbursalAmount) > 0) {
                    throw new GeneralPlatformDomainRuleException(
                            "error.msg.loan.amount.less.than.outstanding.of.loan.to.be.closed",
                            "Topup loan amount should be greater than outstanding amount of loan to be closed.");
                }

                final LoanTopupDetails topupDetails = new LoanTopupDetails(newLoanApplication, loanIdToClose);
                newLoanApplication.setTopupLoanDetails(topupDetails);
            }
        }

        this.loanRepositoryWrapper.save(newLoanApplication);

        if (loanProduct.isInterestRecalculationEnabled()) {
            this.fromApiJsonDeserializer.validateLoanForInterestRecalculation(newLoanApplication);
            createAndPersistCalendarInstanceForInterestRecalculation(newLoanApplication);
        }

        if (newLoanApplication.isAccountNumberRequiresAutoGeneration()) {
            final AccountNumberFormat accountNumberFormat = this.accountNumberFormatRepository
                    .findByAccountType(EntityAccountType.LOAN);
            newLoanApplication.updateAccountNo(
                    this.accountNumberGenerator.generate(newLoanApplication, accountNumberFormat));
            this.loanRepositoryWrapper.save(newLoanApplication);
        }

        final String submittedOnNote = command.stringValueOfParameterNamed("submittedOnNote");
        if (StringUtils.isNotBlank(submittedOnNote)) {
            final Note note = Note.loanNote(newLoanApplication, submittedOnNote);
            this.noteRepository.save(note);
        }

        // Save calendar instance
        final Long calendarId = command.longValueOfParameterNamed("calendarId");
        Calendar calendar = null;

        if (calendarId != null && calendarId != 0) {
            calendar = this.calendarRepository.findOne(calendarId);
            if (calendar == null) {
                throw new CalendarNotFoundException(calendarId);
            }

            final CalendarInstance calendarInstance = new CalendarInstance(calendar, newLoanApplication.getId(),
                    CalendarEntityType.LOANS.getValue());
            this.calendarInstanceRepository.save(calendarInstance);
        } else {
            final LoanApplicationTerms loanApplicationTerms = this.loanScheduleAssembler
                    .assembleLoanTerms(command.parsedJson());
            final Integer repaymentFrequencyNthDayType = command
                    .integerValueOfParameterNamed("repaymentFrequencyNthDayType");
            if (loanApplicationTerms.getRepaymentPeriodFrequencyType() == PeriodFrequencyType.MONTHS
                    && repaymentFrequencyNthDayType != null) {
                final String title = "loan_schedule_" + newLoanApplication.getId();
                LocalDate calendarStartDate = loanApplicationTerms.getRepaymentsStartingFromLocalDate();
                if (calendarStartDate == null)
                    calendarStartDate = loanApplicationTerms.getExpectedDisbursementDate();
                final CalendarFrequencyType calendarFrequencyType = CalendarFrequencyType.MONTHLY;
                final Integer frequency = loanApplicationTerms.getRepaymentEvery();
                final Integer repeatsOnDay = loanApplicationTerms.getWeekDayType().getValue();
                final Integer repeatsOnNthDayOfMonth = loanApplicationTerms.getNthDay();
                final Integer calendarEntityType = CalendarEntityType.LOANS.getValue();
                final Calendar loanCalendar = Calendar.createRepeatingCalendar(title, calendarStartDate,
                        CalendarType.COLLECTION.getValue(), calendarFrequencyType, frequency, repeatsOnDay,
                        repeatsOnNthDayOfMonth);
                this.calendarRepository.save(loanCalendar);
                final CalendarInstance calendarInstance = CalendarInstance.from(loanCalendar,
                        newLoanApplication.getId(), calendarEntityType);
                this.calendarInstanceRepository.save(calendarInstance);
            }
        }

        // Save linked account information
        final Long savingsAccountId = command.longValueOfParameterNamed("linkAccountId");
        if (savingsAccountId != null) {
            final SavingsAccount savingsAccount = this.savingsAccountAssembler.assembleFrom(savingsAccountId);
            this.fromApiJsonDeserializer.validatelinkedSavingsAccount(savingsAccount, newLoanApplication);
            boolean isActive = true;
            final AccountAssociations accountAssociations = AccountAssociations.associateSavingsAccount(
                    newLoanApplication, savingsAccount,
                    AccountAssociationType.LINKED_ACCOUNT_ASSOCIATION.getValue(), isActive);
            this.accountAssociationsRepository.save(accountAssociations);
        }

        if (command.parameterExists(LoanApiConstants.datatables)) {
            this.entityDatatableChecksWritePlatformService.saveDatatables(
                    StatusEnum.CREATE.getCode().longValue(), EntityTables.LOAN.getName(),
                    newLoanApplication.getId(), newLoanApplication.productId(),
                    command.arrayOfParameterNamed(LoanApiConstants.datatables));
        }

        this.entityDatatableChecksWritePlatformService.runTheCheckForProduct(newLoanApplication.getId(),
                EntityTables.LOAN.getName(), StatusEnum.CREATE.getCode().longValue(),
                EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), newLoanApplication.productId());

        return new CommandProcessingResultBuilder() //
                .withCommandId(command.commandId()) //
                .withEntityId(newLoanApplication.getId()) //
                .withOfficeId(newLoanApplication.getOfficeId()) //
                .withClientId(newLoanApplication.getClientId()) //
                .withGroupId(newLoanApplication.getGroupId()) //
                .withLoanId(newLoanApplication.getId()) //
                .build();
    } catch (final DataIntegrityViolationException dve) {
        handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
        return CommandProcessingResult.empty();
    } catch (final PersistenceException dve) {
        Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
        handleDataIntegrityIssues(command, throwable, dve);
        return CommandProcessingResult.empty();
    }
}

From source file:com.gst.infrastructure.dataqueries.service.ReadWriteNonCoreDataServiceImpl.java

@Transactional
@Override/*from   w  ww  . j  a  v  a2  s .  c om*/
public void deleteDatatable(final String datatableName) {

    try {
        this.context.authenticatedUser();
        if (!isRegisteredDataTable(datatableName)) {
            throw new DatatableNotFoundException(datatableName);
        }
        validateDatatableName(datatableName);
        assertDataTableEmpty(datatableName);
        deregisterDatatable(datatableName);
        String[] sqlArray = null;
        if (this.configurationDomainService.isConstraintApproachEnabledForDatatables()) {
            final String deleteColumnCodeSql = "delete from x_table_column_code_mappings where column_alias_name like'"
                    + datatableName.toLowerCase().replaceAll("\\s", "_") + "_%'";
            sqlArray = new String[2];
            sqlArray[1] = deleteColumnCodeSql;
        } else {
            sqlArray = new String[1];
        }
        final String sql = "DROP TABLE `" + datatableName + "`";
        sqlArray[0] = sql;
        this.jdbcTemplate.batchUpdate(sqlArray);
    } catch (final DataIntegrityViolationException e) {
        final Throwable realCause = e.getCause();
        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
                .resource("datatable");
        if (realCause.getMessage().contains("Unknown table")) {
            baseDataValidator.reset().parameter("datatableName").failWithCode("does.not.exist");
        }

        throwExceptionIfValidationWarningsExist(dataValidationErrors);
    }
}

From source file:com.gst.infrastructure.dataqueries.service.ReadWriteNonCoreDataServiceImpl.java

@Transactional
private void _registerDataTable(final String applicationTableName, final String dataTableName,
        final Integer category, final String permissionsSql) {

    validateAppTable(applicationTableName);
    assertDataTableExists(dataTableName);

    final String registerDatatableSql = "insert into x_registered_table (registered_table_name, application_table_name,category) values ('"
            + dataTableName + "', '" + applicationTableName + "', '" + category + "')";

    try {/*from  ww w.j av  a 2 s. c om*/

        final String[] sqlArray = { registerDatatableSql, permissionsSql };
        this.jdbcTemplate.batchUpdate(sqlArray);

        // add the registered table to the config if it is a ppi
        if (this.isSurveyCategory(category)) {
            this.jdbcTemplate.execute("insert into c_configuration (name, value, enabled ) values('"
                    + dataTableName + "', '0','0')");
        }

    } catch (final DataIntegrityViolationException dve) {
        final Throwable cause = dve.getCause();
        final Throwable realCause = dve.getMostSpecificCause();
        // even if duplicate is only due to permission duplicate, okay to
        // show duplicate datatable error msg
        if (realCause.getMessage().contains("Duplicate entry")
                || cause.getMessage().contains("Duplicate entry")) {
            throw new PlatformDataIntegrityException("error.msg.datatable.registered",
                    "Datatable `" + dataTableName + "` is already registered against an application table.",
                    "dataTableName", dataTableName);
        }
        logAsErrorUnexpectedDataIntegrityException(dve);
        throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue",
                "Unknown data integrity issue with resource.");
    } catch (final PersistenceException dve) {
        final Throwable cause = dve.getCause();
        if (cause.getMessage().contains("Duplicate entry")) {
            throw new PlatformDataIntegrityException("error.msg.datatable.registered",
                    "Datatable `" + dataTableName + "` is already registered against an application table.",
                    "dataTableName", dataTableName);
        }
        logAsErrorUnexpectedDataIntegrityException(dve);
        throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue",
                "Unknown data integrity issue with resource.");
    }

}

From source file:com.gst.infrastructure.dataqueries.service.ReadWriteNonCoreDataServiceImpl.java

@Transactional
@Override/* w  w  w.j  a v  a  2 s .c o  m*/
public CommandProcessingResult createDatatable(final JsonCommand command) {

    String datatableName = null;

    try {
        this.context.authenticatedUser();
        this.fromApiJsonDeserializer.validateForCreate(command.json());

        final JsonElement element = this.fromJsonHelper.parse(command.json());
        final JsonArray columns = this.fromJsonHelper.extractJsonArrayNamed("columns", element);
        datatableName = this.fromJsonHelper.extractStringNamed("datatableName", element);
        final String apptableName = this.fromJsonHelper.extractStringNamed("apptableName", element);
        Boolean multiRow = this.fromJsonHelper.extractBooleanNamed("multiRow", element);

        /***
         * In cases of tables storing hierarchical entities (like m_group),
         * different entities would end up being stored in the same table.
         * 
         * Ex: Centers are a specific type of group, add abstractions for
         * the same
         ***/
        final String actualAppTableName = mapToActualAppTable(apptableName);

        if (multiRow == null) {
            multiRow = false;
        }

        validateDatatableName(datatableName);
        validateAppTable(apptableName);
        final boolean isConstraintApproach = this.configurationDomainService
                .isConstraintApproachEnabledForDatatables();
        final String fkColumnName = apptableName.substring(2) + "_id";
        final String dataTableNameAlias = datatableName.toLowerCase().replaceAll("\\s", "_");
        final String fkName = dataTableNameAlias + "_" + fkColumnName;
        StringBuilder sqlBuilder = new StringBuilder();
        final StringBuilder constrainBuilder = new StringBuilder();
        final Map<String, Long> codeMappings = new HashMap<>();
        sqlBuilder = sqlBuilder.append("CREATE TABLE `" + datatableName + "` (");

        if (multiRow) {
            sqlBuilder = sqlBuilder.append("`id` BIGINT(20) NOT NULL AUTO_INCREMENT, ")
                    .append("`" + fkColumnName + "` BIGINT(20) NOT NULL, ");
        } else {
            sqlBuilder = sqlBuilder.append("`" + fkColumnName + "` BIGINT(20) NOT NULL, ");
        }

        for (final JsonElement column : columns) {
            parseDatatableColumnObjectForCreate(column.getAsJsonObject(), sqlBuilder, constrainBuilder,
                    dataTableNameAlias, codeMappings, isConstraintApproach);
        }

        // Remove trailing comma and space
        sqlBuilder = sqlBuilder.delete(sqlBuilder.length() - 2, sqlBuilder.length());

        if (multiRow) {
            sqlBuilder = sqlBuilder.append(", PRIMARY KEY (`id`)")
                    .append(", KEY `fk_" + apptableName.substring(2) + "_id` (`" + fkColumnName + "`)")
                    .append(", CONSTRAINT `fk_" + fkName + "` ").append("FOREIGN KEY (`" + fkColumnName + "`) ")
                    .append("REFERENCES `" + actualAppTableName + "` (`id`)");
        } else {
            sqlBuilder = sqlBuilder.append(", PRIMARY KEY (`" + fkColumnName + "`)")
                    .append(", CONSTRAINT `fk_" + fkName + "` ").append("FOREIGN KEY (`" + fkColumnName + "`) ")
                    .append("REFERENCES `" + actualAppTableName + "` (`id`)");
        }

        sqlBuilder.append(constrainBuilder);

        sqlBuilder = sqlBuilder.append(") ENGINE=InnoDB DEFAULT CHARSET=utf8;");
        this.jdbcTemplate.execute(sqlBuilder.toString());

        registerDatatable(datatableName, apptableName);
        registerColumnCodeMapping(codeMappings);
    } catch (final DataIntegrityViolationException e) {
        final Throwable realCause = e.getCause();
        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
                .resource("datatable");

        if (realCause.getMessage().toLowerCase().contains("duplicate column name")) {
            baseDataValidator.reset().parameter("name").failWithCode("duplicate.column.name");
        } else if (realCause.getMessage().contains("Table")
                && realCause.getMessage().contains("already exists")) {
            baseDataValidator.reset().parameter("datatableName").value(datatableName)
                    .failWithCode("datatable.already.exists");
        } else if (realCause.getMessage().contains("Column") && realCause.getMessage().contains("big")) {
            baseDataValidator.reset().parameter("column").failWithCode("length.too.big");
        } else if (realCause.getMessage().contains("Row") && realCause.getMessage().contains("large")) {
            baseDataValidator.reset().parameter("row").failWithCode("size.too.large");
        }

        throwExceptionIfValidationWarningsExist(dataValidationErrors);
    } catch (final PersistenceException | BadSqlGrammarException ee) {
        Throwable realCause = ExceptionUtils.getRootCause(ee.getCause());
        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
                .resource("datatable");
        if (realCause.getMessage().toLowerCase().contains("duplicate column name")) {
            baseDataValidator.reset().parameter("name").failWithCode("duplicate.column.name");
        } else if (realCause.getMessage().contains("Table")
                && realCause.getMessage().contains("already exists")) {
            baseDataValidator.reset().parameter("datatableName").value(datatableName)
                    .failWithCode("datatable.already.exists");
        } else if (realCause.getMessage().contains("Column") && realCause.getMessage().contains("big")) {
            baseDataValidator.reset().parameter("column").failWithCode("length.too.big");
        } else if (realCause.getMessage().contains("Row") && realCause.getMessage().contains("large")) {
            baseDataValidator.reset().parameter("row").failWithCode("size.too.large");
        }

        throwExceptionIfValidationWarningsExist(dataValidationErrors);
    }

    return new CommandProcessingResultBuilder().withCommandId(command.commandId())
            .withResourceIdAsString(datatableName).build();
}

From source file:com.gst.portfolio.loanaccount.service.LoanApplicationWritePlatformServiceJpaRepositoryImpl.java

@Transactional
@Override//  www .jav  a2 s  .c o  m
public CommandProcessingResult modifyApplication(final Long loanId, final JsonCommand command) {

    try {
        AppUser currentUser = getAppUserIfPresent();
        final Loan existingLoanApplication = retrieveLoanBy(loanId);
        if (!existingLoanApplication.isSubmittedAndPendingApproval()) {
            throw new LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified(loanId);
        }

        final String productIdParamName = "productId";
        LoanProduct newLoanProduct = null;
        if (command.isChangeInLongParameterNamed(productIdParamName,
                existingLoanApplication.loanProduct().getId())) {
            final Long productId = command.longValueOfParameterNamed(productIdParamName);
            newLoanProduct = this.loanProductRepository.findOne(productId);
            if (newLoanProduct == null) {
                throw new LoanProductNotFoundException(productId);
            }
        }

        LoanProduct loanProductForValidations = newLoanProduct == null ? existingLoanApplication.loanProduct()
                : newLoanProduct;

        this.fromApiJsonDeserializer.validateForModify(command.json(), loanProductForValidations,
                existingLoanApplication);

        checkClientOrGroupActive(existingLoanApplication);

        final Set<LoanCharge> existingCharges = existingLoanApplication.charges();
        Map<Long, LoanChargeData> chargesMap = new HashMap<>();
        for (LoanCharge charge : existingCharges) {
            LoanChargeData chargeData = new LoanChargeData(charge.getId(), charge.getDueLocalDate(),
                    charge.amountOrPercentage());
            chargesMap.put(charge.getId(), chargeData);
        }
        List<LoanDisbursementDetails> disbursementDetails = this.loanUtilService
                .fetchDisbursementData(command.parsedJson().getAsJsonObject());

        /**
         * Stores all charges which are passed in during modify loan
         * application
         **/
        final Set<LoanCharge> possiblyModifedLoanCharges = this.loanChargeAssembler
                .fromParsedJson(command.parsedJson(), disbursementDetails);
        /** Boolean determines if any charge has been modified **/
        boolean isChargeModified = false;

        Set<Charge> newTrancheChages = this.loanChargeAssembler.getNewLoanTrancheCharges(command.parsedJson());
        for (Charge charge : newTrancheChages) {
            existingLoanApplication.addTrancheLoanCharge(charge);
        }

        /**
         * If there are any charges already present, which are now not
         * passed in as a part of the request, deem the charges as modified
         **/
        if (!possiblyModifedLoanCharges.isEmpty()) {
            if (!possiblyModifedLoanCharges.containsAll(existingCharges)) {
                isChargeModified = true;
            }
        }

        /**
         * If any new charges are added or values of existing charges are
         * modified
         **/
        for (LoanCharge loanCharge : possiblyModifedLoanCharges) {
            if (loanCharge.getId() == null) {
                isChargeModified = true;
            } else {
                LoanChargeData chargeData = chargesMap.get(loanCharge.getId());
                if (loanCharge.amountOrPercentage().compareTo(chargeData.amountOrPercentage()) != 0
                        || (loanCharge.isSpecifiedDueDate()
                                && !loanCharge.getDueLocalDate().equals(chargeData.getDueDate()))) {
                    isChargeModified = true;
                }
            }
        }

        final Set<LoanCollateral> possiblyModifedLoanCollateralItems = this.loanCollateralAssembler
                .fromParsedJson(command.parsedJson());

        final Map<String, Object> changes = existingLoanApplication.loanApplicationModification(command,
                possiblyModifedLoanCharges, possiblyModifedLoanCollateralItems, this.aprCalculator,
                isChargeModified);

        if (changes.containsKey("expectedDisbursementDate")) {
            this.loanAssembler.validateExpectedDisbursementForHolidayAndNonWorkingDay(existingLoanApplication);
        }

        final String clientIdParamName = "clientId";
        if (changes.containsKey(clientIdParamName)) {
            final Long clientId = command.longValueOfParameterNamed(clientIdParamName);
            final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
            if (client.isNotActive()) {
                throw new ClientNotActiveException(clientId);
            }

            existingLoanApplication.updateClient(client);
        }

        final String groupIdParamName = "groupId";
        if (changes.containsKey(groupIdParamName)) {
            final Long groupId = command.longValueOfParameterNamed(groupIdParamName);
            final Group group = this.groupRepository.findOneWithNotFoundDetection(groupId);
            if (group.isNotActive()) {
                throw new GroupNotActiveException(groupId);
            }

            existingLoanApplication.updateGroup(group);
        }

        if (newLoanProduct != null) {
            existingLoanApplication.updateLoanProduct(newLoanProduct);
            if (!changes.containsKey("interestRateFrequencyType")) {
                existingLoanApplication.updateInterestRateFrequencyType();
            }
            final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
            final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
                    .resource("loan");
            if (newLoanProduct.useBorrowerCycle()) {
                final Long clientId = this.fromJsonHelper.extractLongNamed("clientId", command.parsedJson());
                final Long groupId = this.fromJsonHelper.extractLongNamed("groupId", command.parsedJson());
                Integer cycleNumber = 0;
                if (clientId != null) {
                    cycleNumber = this.loanReadPlatformService.retriveLoanCounter(clientId,
                            newLoanProduct.getId());
                } else if (groupId != null) {
                    cycleNumber = this.loanReadPlatformService.retriveLoanCounter(groupId,
                            AccountType.GROUP.getValue(), newLoanProduct.getId());
                }
                this.loanProductCommandFromApiJsonDeserializer.validateMinMaxConstraints(command.parsedJson(),
                        baseDataValidator, newLoanProduct, cycleNumber);
            } else {
                this.loanProductCommandFromApiJsonDeserializer.validateMinMaxConstraints(command.parsedJson(),
                        baseDataValidator, newLoanProduct);
            }
            if (newLoanProduct.isLinkedToFloatingInterestRate()) {
                existingLoanApplication.getLoanProductRelatedDetail().updateForFloatingInterestRates();
            } else {
                existingLoanApplication.setInterestRateDifferential(null);
                existingLoanApplication.setIsFloatingInterestRate(null);
            }
            if (!dataValidationErrors.isEmpty()) {
                throw new PlatformApiDataValidationException(dataValidationErrors);
            }
        }

        existingLoanApplication.updateIsInterestRecalculationEnabled();
        validateSubmittedOnDate(existingLoanApplication);

        final LoanProductRelatedDetail productRelatedDetail = existingLoanApplication.repaymentScheduleDetail();
        if (existingLoanApplication.loanProduct().getLoanProductConfigurableAttributes() != null) {
            updateProductRelatedDetails(productRelatedDetail, existingLoanApplication);
        }

        if (existingLoanApplication.getLoanProduct().canUseForTopup()
                && existingLoanApplication.getClientId() != null) {
            final Boolean isTopup = command.booleanObjectValueOfParameterNamed(LoanApiConstants.isTopup);
            if (command.isChangeInBooleanParameterNamed(LoanApiConstants.isTopup,
                    existingLoanApplication.isTopup())) {
                existingLoanApplication.setIsTopup(isTopup);
                changes.put(LoanApiConstants.isTopup, isTopup);
            }

            if (existingLoanApplication.isTopup()) {
                final Long loanIdToClose = command.longValueOfParameterNamed(LoanApiConstants.loanIdToClose);
                LoanTopupDetails existingLoanTopupDetails = existingLoanApplication.getTopupLoanDetails();
                if (existingLoanTopupDetails == null
                        || (existingLoanTopupDetails != null
                                && existingLoanTopupDetails.getLoanIdToClose() != loanIdToClose)
                        || changes.containsKey("submittedOnDate")
                        || changes.containsKey("expectedDisbursementDate") || changes.containsKey("principal")
                        || changes.containsKey(LoanApiConstants.disbursementDataParameterName)) {
                    Long existingLoanIdToClose = null;
                    if (existingLoanTopupDetails != null) {
                        existingLoanIdToClose = existingLoanTopupDetails.getLoanIdToClose();
                    }
                    final Loan loanToClose = this.loanRepositoryWrapper.findNonClosedLoanThatBelongsToClient(
                            loanIdToClose, existingLoanApplication.getClientId());
                    if (loanToClose == null) {
                        throw new GeneralPlatformDomainRuleException(
                                "error.msg.loan.loanIdToClose.no.active.loan.associated.to.client.found",
                                "loanIdToClose is invalid, No Active Loan associated with the given Client ID found.");
                    }
                    if (loanToClose.isMultiDisburmentLoan()
                            && !loanToClose.isInterestRecalculationEnabledForProduct()) {
                        throw new GeneralPlatformDomainRuleException(
                                "error.msg.loan.topup.on.multi.tranche.loan.without.interest.recalculation.not.supported",
                                "Topup on loan with multi-tranche disbursal and without interest recalculation is not supported.");
                    }
                    final LocalDate disbursalDateOfLoanToClose = loanToClose.getDisbursementDate();
                    if (!existingLoanApplication.getSubmittedOnDate().isAfter(disbursalDateOfLoanToClose)) {
                        throw new GeneralPlatformDomainRuleException(
                                "error.msg.loan.submitted.date.should.be.after.topup.loan.disbursal.date",
                                "Submitted date of this loan application "
                                        + existingLoanApplication.getSubmittedOnDate()
                                        + " should be after the disbursed date of loan to be closed "
                                        + disbursalDateOfLoanToClose);
                    }
                    if (!loanToClose.getCurrencyCode().equals(existingLoanApplication.getCurrencyCode())) {
                        throw new GeneralPlatformDomainRuleException(
                                "error.msg.loan.to.be.closed.has.different.currency",
                                "loanIdToClose is invalid, Currency code is different.");
                    }
                    final LocalDate lastUserTransactionOnLoanToClose = loanToClose.getLastUserTransactionDate();
                    if (!existingLoanApplication.getDisbursementDate()
                            .isAfter(lastUserTransactionOnLoanToClose)) {
                        throw new GeneralPlatformDomainRuleException(
                                "error.msg.loan.disbursal.date.should.be.after.last.transaction.date.of.loan.to.be.closed",
                                "Disbursal date of this loan application "
                                        + existingLoanApplication.getDisbursementDate()
                                        + " should be after last transaction date of loan to be closed "
                                        + lastUserTransactionOnLoanToClose);
                    }
                    BigDecimal loanOutstanding = this.loanReadPlatformService.retrieveLoanPrePaymentTemplate(
                            loanIdToClose, existingLoanApplication.getDisbursementDate()).getAmount();
                    final BigDecimal firstDisbursalAmount = existingLoanApplication.getFirstDisbursalAmount();
                    if (loanOutstanding.compareTo(firstDisbursalAmount) > 0) {
                        throw new GeneralPlatformDomainRuleException(
                                "error.msg.loan.amount.less.than.outstanding.of.loan.to.be.closed",
                                "Topup loan amount should be greater than outstanding amount of loan to be closed.");
                    }

                    if (existingLoanIdToClose != loanIdToClose) {
                        final LoanTopupDetails topupDetails = new LoanTopupDetails(existingLoanApplication,
                                loanIdToClose);
                        existingLoanApplication.setTopupLoanDetails(topupDetails);
                        changes.put(LoanApiConstants.loanIdToClose, loanIdToClose);
                    }
                }
            } else {
                existingLoanApplication.setTopupLoanDetails(null);
            }
        } else {
            if (existingLoanApplication.isTopup()) {
                existingLoanApplication.setIsTopup(false);
                existingLoanApplication.setTopupLoanDetails(null);
                changes.put(LoanApiConstants.isTopup, false);
            }
        }

        final String fundIdParamName = "fundId";
        if (changes.containsKey(fundIdParamName)) {
            final Long fundId = command.longValueOfParameterNamed(fundIdParamName);
            final Fund fund = this.loanAssembler.findFundByIdIfProvided(fundId);

            existingLoanApplication.updateFund(fund);
        }

        final String loanPurposeIdParamName = "loanPurposeId";
        if (changes.containsKey(loanPurposeIdParamName)) {
            final Long loanPurposeId = command.longValueOfParameterNamed(loanPurposeIdParamName);
            final CodeValue loanPurpose = this.loanAssembler.findCodeValueByIdIfProvided(loanPurposeId);
            existingLoanApplication.updateLoanPurpose(loanPurpose);
        }

        final String loanOfficerIdParamName = "loanOfficerId";
        if (changes.containsKey(loanOfficerIdParamName)) {
            final Long loanOfficerId = command.longValueOfParameterNamed(loanOfficerIdParamName);
            final Staff newValue = this.loanAssembler.findLoanOfficerByIdIfProvided(loanOfficerId);
            existingLoanApplication.updateLoanOfficerOnLoanApplication(newValue);
        }

        final String strategyIdParamName = "transactionProcessingStrategyId";
        if (changes.containsKey(strategyIdParamName)) {
            final Long strategyId = command.longValueOfParameterNamed(strategyIdParamName);
            final LoanTransactionProcessingStrategy strategy = this.loanAssembler
                    .findStrategyByIdIfProvided(strategyId);

            existingLoanApplication.updateTransactionProcessingStrategy(strategy);
        }

        final String collateralParamName = "collateral";
        if (changes.containsKey(collateralParamName)) {
            final Set<LoanCollateral> loanCollateral = this.loanCollateralAssembler
                    .fromParsedJson(command.parsedJson());
            existingLoanApplication.updateLoanCollateral(loanCollateral);
        }

        final String chargesParamName = "charges";
        if (changes.containsKey(chargesParamName)) {
            existingLoanApplication.updateLoanCharges(possiblyModifedLoanCharges);
        }

        if (changes.containsKey("recalculateLoanSchedule")) {
            changes.remove("recalculateLoanSchedule");

            final JsonElement parsedQuery = this.fromJsonHelper.parse(command.json());
            final JsonQuery query = JsonQuery.from(command.json(), parsedQuery, this.fromJsonHelper);

            final LoanScheduleModel loanSchedule = this.calculationPlatformService.calculateLoanSchedule(query,
                    false);
            existingLoanApplication.updateLoanSchedule(loanSchedule, currentUser);
            existingLoanApplication.recalculateAllCharges();
        }

        this.fromApiJsonDeserializer.validateLoanTermAndRepaidEveryValues(
                existingLoanApplication.getTermFrequency(),
                existingLoanApplication.getTermPeriodFrequencyType(),
                productRelatedDetail.getNumberOfRepayments(), productRelatedDetail.getRepayEvery(),
                productRelatedDetail.getRepaymentPeriodFrequencyType().getValue(), existingLoanApplication);

        saveAndFlushLoanWithDataIntegrityViolationChecks(existingLoanApplication);

        final String submittedOnNote = command.stringValueOfParameterNamed("submittedOnNote");
        if (StringUtils.isNotBlank(submittedOnNote)) {
            final Note note = Note.loanNote(existingLoanApplication, submittedOnNote);
            this.noteRepository.save(note);
        }

        final Long calendarId = command.longValueOfParameterNamed("calendarId");
        Calendar calendar = null;
        if (calendarId != null && calendarId != 0) {
            calendar = this.calendarRepository.findOne(calendarId);
            if (calendar == null) {
                throw new CalendarNotFoundException(calendarId);
            }
        }

        final List<CalendarInstance> ciList = (List<CalendarInstance>) this.calendarInstanceRepository
                .findByEntityIdAndEntityTypeId(loanId, CalendarEntityType.LOANS.getValue());
        if (calendar != null) {

            // For loans, allow to attach only one calendar instance per
            // loan
            if (ciList != null && !ciList.isEmpty()) {
                final CalendarInstance calendarInstance = ciList.get(0);
                final boolean isCalendarAssociatedWithEntity = this.calendarReadPlatformService
                        .isCalendarAssociatedWithEntity(calendarInstance.getEntityId(),
                                calendarInstance.getCalendar().getId(),
                                CalendarEntityType.LOANS.getValue().longValue());
                if (isCalendarAssociatedWithEntity) {
                    this.calendarRepository.delete(calendarInstance.getCalendar());
                }
                if (calendarInstance.getCalendar().getId() != calendar.getId()) {
                    calendarInstance.updateCalendar(calendar);
                    this.calendarInstanceRepository.saveAndFlush(calendarInstance);
                }
            } else {
                // attaching new calendar
                final CalendarInstance calendarInstance = new CalendarInstance(calendar,
                        existingLoanApplication.getId(), CalendarEntityType.LOANS.getValue());
                this.calendarInstanceRepository.save(calendarInstance);
            }

        } else {
            if (ciList != null && !ciList.isEmpty()) {
                final CalendarInstance existingCalendarInstance = ciList.get(0);
                final boolean isCalendarAssociatedWithEntity = this.calendarReadPlatformService
                        .isCalendarAssociatedWithEntity(existingCalendarInstance.getEntityId(),
                                existingCalendarInstance.getCalendar().getId(),
                                CalendarEntityType.GROUPS.getValue().longValue());
                if (isCalendarAssociatedWithEntity) {
                    this.calendarInstanceRepository.delete(existingCalendarInstance);
                }
            }
            if (changes.containsKey("repaymentFrequencyNthDayType")
                    || changes.containsKey("repaymentFrequencyDayOfWeekType")) {
                if (changes.get("repaymentFrequencyNthDayType") == null) {
                    if (ciList != null && !ciList.isEmpty()) {
                        final CalendarInstance calendarInstance = ciList.get(0);
                        final boolean isCalendarAssociatedWithEntity = this.calendarReadPlatformService
                                .isCalendarAssociatedWithEntity(calendarInstance.getEntityId(),
                                        calendarInstance.getCalendar().getId(),
                                        CalendarEntityType.LOANS.getValue().longValue());
                        if (isCalendarAssociatedWithEntity) {
                            this.calendarInstanceRepository.delete(calendarInstance);
                            this.calendarRepository.delete(calendarInstance.getCalendar());
                        }
                    }
                } else {
                    Integer repaymentFrequencyTypeInt = command
                            .integerValueOfParameterNamed("repaymentFrequencyType");
                    if (repaymentFrequencyTypeInt != null) {
                        if (PeriodFrequencyType
                                .fromInt(repaymentFrequencyTypeInt) == PeriodFrequencyType.MONTHS) {
                            final String title = "loan_schedule_" + existingLoanApplication.getId();
                            final Integer typeId = CalendarType.COLLECTION.getValue();
                            final CalendarFrequencyType repaymentFrequencyType = CalendarFrequencyType.MONTHLY;
                            final Integer interval = command.integerValueOfParameterNamed("repaymentEvery");
                            LocalDate startDate = command
                                    .localDateValueOfParameterNamed("repaymentsStartingFromDate");
                            if (startDate == null)
                                startDate = command.localDateValueOfParameterNamed("expectedDisbursementDate");
                            final Calendar newCalendar = Calendar.createRepeatingCalendar(title, startDate,
                                    typeId, repaymentFrequencyType, interval,
                                    (Integer) changes.get("repaymentFrequencyDayOfWeekType"),
                                    (Integer) changes.get("repaymentFrequencyNthDayType"));
                            if (ciList != null && !ciList.isEmpty()) {
                                final CalendarInstance calendarInstance = ciList.get(0);
                                final boolean isCalendarAssociatedWithEntity = this.calendarReadPlatformService
                                        .isCalendarAssociatedWithEntity(calendarInstance.getEntityId(),
                                                calendarInstance.getCalendar().getId(),
                                                CalendarEntityType.LOANS.getValue().longValue());
                                if (isCalendarAssociatedWithEntity) {
                                    final Calendar existingCalendar = calendarInstance.getCalendar();
                                    if (existingCalendar != null) {
                                        String existingRecurrence = existingCalendar.getRecurrence();
                                        if (!existingRecurrence.equals(newCalendar.getRecurrence())) {
                                            existingCalendar.setRecurrence(newCalendar.getRecurrence());
                                            this.calendarRepository.save(existingCalendar);
                                        }
                                    }
                                }
                            } else {
                                this.calendarRepository.save(newCalendar);
                                final Integer calendarEntityType = CalendarEntityType.LOANS.getValue();
                                final CalendarInstance calendarInstance = new CalendarInstance(newCalendar,
                                        existingLoanApplication.getId(), calendarEntityType);
                                this.calendarInstanceRepository.save(calendarInstance);
                            }
                        }
                    }
                }
            }
        }

        // Save linked account information
        final String linkAccountIdParamName = "linkAccountId";
        final Long savingsAccountId = command.longValueOfParameterNamed(linkAccountIdParamName);
        AccountAssociations accountAssociations = this.accountAssociationsRepository.findByLoanIdAndType(loanId,
                AccountAssociationType.LINKED_ACCOUNT_ASSOCIATION.getValue());
        boolean isLinkedAccPresent = false;
        if (savingsAccountId == null) {
            if (accountAssociations != null) {
                if (this.fromJsonHelper.parameterExists(linkAccountIdParamName, command.parsedJson())) {
                    this.accountAssociationsRepository.delete(accountAssociations);
                    changes.put(linkAccountIdParamName, null);
                } else {
                    isLinkedAccPresent = true;
                }
            }
        } else {
            isLinkedAccPresent = true;
            boolean isModified = false;
            if (accountAssociations == null) {
                isModified = true;
            } else {
                final SavingsAccount savingsAccount = accountAssociations.linkedSavingsAccount();
                if (savingsAccount == null || !savingsAccount.getId().equals(savingsAccountId)) {
                    isModified = true;
                }
            }
            if (isModified) {
                final SavingsAccount savingsAccount = this.savingsAccountAssembler
                        .assembleFrom(savingsAccountId);
                this.fromApiJsonDeserializer.validatelinkedSavingsAccount(savingsAccount,
                        existingLoanApplication);
                if (accountAssociations == null) {
                    boolean isActive = true;
                    accountAssociations = AccountAssociations.associateSavingsAccount(existingLoanApplication,
                            savingsAccount, AccountAssociationType.LINKED_ACCOUNT_ASSOCIATION.getValue(),
                            isActive);
                } else {
                    accountAssociations.updateLinkedSavingsAccount(savingsAccount);
                }
                changes.put(linkAccountIdParamName, savingsAccountId);
                this.accountAssociationsRepository.save(accountAssociations);
            }
        }

        if (!isLinkedAccPresent) {
            final Set<LoanCharge> charges = existingLoanApplication.charges();
            for (final LoanCharge loanCharge : charges) {
                if (loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
                    final String errorMessage = "one of the charges requires linked savings account for payment";
                    throw new LinkedAccountRequiredException("loanCharge", errorMessage);
                }
            }
        }

        if ((command.longValueOfParameterNamed(productIdParamName) != null)
                || (command.longValueOfParameterNamed(clientIdParamName) != null)
                || (command.longValueOfParameterNamed(groupIdParamName) != null)) {
            Long OfficeId = null;
            if (existingLoanApplication.getClient() != null) {
                OfficeId = existingLoanApplication.getClient().getOffice().getId();
            } else if (existingLoanApplication.getGroup() != null) {
                OfficeId = existingLoanApplication.getGroup().getOffice().getId();
            }
            officeSpecificLoanProductValidation(existingLoanApplication.getLoanProduct().getId(), OfficeId);
        }

        // updating loan interest recalculation details throwing null
        // pointer exception after saveAndFlush
        // http://stackoverflow.com/questions/17151757/hibernate-cascade-update-gives-null-pointer/17334374#17334374
        this.loanRepositoryWrapper.save(existingLoanApplication);

        if (productRelatedDetail.isInterestRecalculationEnabled()) {
            this.fromApiJsonDeserializer.validateLoanForInterestRecalculation(existingLoanApplication);
            if (changes.containsKey(LoanProductConstants.isInterestRecalculationEnabledParameterName)) {
                createAndPersistCalendarInstanceForInterestRecalculation(existingLoanApplication);

            }

        }

        return new CommandProcessingResultBuilder() //
                .withEntityId(loanId) //
                .withOfficeId(existingLoanApplication.getOfficeId()) //
                .withClientId(existingLoanApplication.getClientId()) //
                .withGroupId(existingLoanApplication.getGroupId()) //
                .withLoanId(existingLoanApplication.getId()) //
                .with(changes).build();
    } catch (final DataIntegrityViolationException dve) {
        handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
        return CommandProcessingResult.empty();
    } catch (final PersistenceException dve) {
        Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
        handleDataIntegrityIssues(command, throwable, dve);
        return CommandProcessingResult.empty();
    }
}