Java tutorial
/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package com.gst.infrastructure.campaigns.sms.service; import java.io.IOException; import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.PostConstruct; import com.gst.infrastructure.campaigns.sms.constants.SmsCampaignTriggerType; import com.gst.infrastructure.campaigns.sms.domain.SmsCampaign; import com.gst.infrastructure.campaigns.sms.domain.SmsCampaignRepository; import com.gst.infrastructure.sms.domain.SmsMessage; import com.gst.infrastructure.sms.domain.SmsMessageRepository; import com.gst.infrastructure.sms.scheduler.SmsMessageScheduledJobService; import com.gst.organisation.office.domain.Office; import com.gst.organisation.office.domain.OfficeRepository; import com.gst.portfolio.client.domain.Client; import com.gst.portfolio.common.BusinessEventNotificationConstants; import com.gst.portfolio.common.BusinessEventNotificationConstants.BUSINESS_ENTITY; import com.gst.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS; import com.gst.portfolio.common.service.BusinessEventListner; import com.gst.portfolio.common.service.BusinessEventNotifierService; import com.gst.portfolio.group.domain.Group; import com.gst.portfolio.group.domain.GroupRepository; import com.gst.portfolio.loanaccount.domain.Loan; import com.gst.portfolio.loanaccount.domain.LoanTransaction; import com.gst.portfolio.loanaccount.exception.InvalidLoanTypeException; import com.gst.portfolio.savings.domain.SavingsAccount; import com.gst.portfolio.savings.domain.SavingsAccountTransaction; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.type.TypeReference; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class SmsCampaignDomainServiceImpl implements SmsCampaignDomainService { private static final Logger logger = LoggerFactory.getLogger(SmsCampaignDomainServiceImpl.class); //private final static int POOL_SIZE = 5 ; private final SmsCampaignRepository smsCampaignRepository; private final SmsMessageRepository smsMessageRepository; private final OfficeRepository officeRepository; private final BusinessEventNotifierService businessEventNotifierService; private final SmsCampaignWritePlatformService smsCampaignWritePlatformCommandHandler; private final GroupRepository groupRepository; private final SmsMessageScheduledJobService smsMessageScheduledJobService; @Autowired public SmsCampaignDomainServiceImpl(final SmsCampaignRepository smsCampaignRepository, final SmsMessageRepository smsMessageRepository, final BusinessEventNotifierService businessEventNotifierService, final OfficeRepository officeRepository, final SmsCampaignWritePlatformService smsCampaignWritePlatformCommandHandler, final GroupRepository groupRepository, final SmsMessageScheduledJobService smsMessageScheduledJobService) { this.smsCampaignRepository = smsCampaignRepository; this.smsMessageRepository = smsMessageRepository; this.businessEventNotifierService = businessEventNotifierService; this.officeRepository = officeRepository; this.smsCampaignWritePlatformCommandHandler = smsCampaignWritePlatformCommandHandler; this.groupRepository = groupRepository; this.smsMessageScheduledJobService = smsMessageScheduledJobService; } @PostConstruct public void addListners() { this.businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_APPROVED, new SendSmsOnLoanApproved()); this.businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_REJECTED, new SendSmsOnLoanRejected()); this.businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_MAKE_REPAYMENT, new SendSmsOnLoanRepayment()); this.businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.CLIENTS_ACTIVATE, new ClientActivatedListener()); this.businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.CLIENTS_REJECT, new ClientRejectedListener()); this.businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_ACTIVATE, new SavingsAccountActivatedListener()); this.businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_REJECT, new SavingsAccountRejectedListener()); this.businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_DEPOSIT, new SavingsAccountTransactionListener(true)); this.businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_WITHDRAWAL, new SavingsAccountTransactionListener(false)); } private void notifyRejectedLoanOwner(Loan loan) { List<SmsCampaign> smsCampaigns = retrieveSmsCampaigns("Loan Rejected"); if (smsCampaigns.size() > 0) { for (SmsCampaign campaign : smsCampaigns) { if (campaign.isActive()) { SmsCampaignDomainServiceImpl.this.smsCampaignWritePlatformCommandHandler .insertDirectCampaignIntoSmsOutboundTable(loan, campaign); } } } } private void notifyAcceptedLoanOwner(Loan loan) { List<SmsCampaign> smsCampaigns = retrieveSmsCampaigns("Loan Approved"); if (smsCampaigns.size() > 0) { for (SmsCampaign campaign : smsCampaigns) { this.smsCampaignWritePlatformCommandHandler.insertDirectCampaignIntoSmsOutboundTable(loan, campaign); } } } private void notifyClientActivated(final Client client) { List<SmsCampaign> smsCampaigns = retrieveSmsCampaigns("Client Activated"); if (smsCampaigns.size() > 0) { for (SmsCampaign campaign : smsCampaigns) { this.smsCampaignWritePlatformCommandHandler.insertDirectCampaignIntoSmsOutboundTable(client, campaign); } } } private void notifyClientRejected(final Client client) { List<SmsCampaign> smsCampaigns = retrieveSmsCampaigns("Client Rejected"); if (smsCampaigns.size() > 0) { for (SmsCampaign campaign : smsCampaigns) { this.smsCampaignWritePlatformCommandHandler.insertDirectCampaignIntoSmsOutboundTable(client, campaign); } } } private void notifySavingsAccountActivated(final SavingsAccount savingsAccount) { List<SmsCampaign> smsCampaigns = retrieveSmsCampaigns("Savings Activated"); if (smsCampaigns.size() > 0) { for (SmsCampaign campaign : smsCampaigns) { this.smsCampaignWritePlatformCommandHandler.insertDirectCampaignIntoSmsOutboundTable(savingsAccount, campaign); } } } private void notifySavingsAccountRejected(final SavingsAccount savingsAccount) { List<SmsCampaign> smsCampaigns = retrieveSmsCampaigns("Savings Rejected"); if (smsCampaigns.size() > 0) { for (SmsCampaign campaign : smsCampaigns) { this.smsCampaignWritePlatformCommandHandler.insertDirectCampaignIntoSmsOutboundTable(savingsAccount, campaign); } } } private void sendSmsForLoanRepayment(LoanTransaction loanTransaction) { List<SmsCampaign> smsCampaigns = retrieveSmsCampaigns("Loan Repayment"); if (smsCampaigns.size() > 0) { for (SmsCampaign smsCampaign : smsCampaigns) { try { Loan loan = loanTransaction.getLoan(); final Set<Client> groupClients = new HashSet<>(); if (loan.hasInvalidLoanType()) { throw new InvalidLoanTypeException( "Loan Type cannot be Invalid for the Triggered Sms Campaign"); } if (loan.isGroupLoan()) { Group group = this.groupRepository.findOne(loan.getGroupId()); groupClients.addAll(group.getClientMembers()); } else { groupClients.add(loan.client()); } HashMap<String, String> campaignParams = new ObjectMapper() .readValue(smsCampaign.getParamValue(), new TypeReference<HashMap<String, String>>() { }); if (groupClients.size() > 0) { for (Client client : groupClients) { HashMap<String, Object> smsParams = processRepaymentDataForSms(loanTransaction, client); for (String key : campaignParams.keySet()) { String value = campaignParams.get(key); String spvalue = null; boolean spkeycheck = smsParams.containsKey(key); if (spkeycheck) { spvalue = smsParams.get(key).toString(); } if (spkeycheck && !(value.equals("-1") || spvalue.equals(value))) { if (key.equals("officeId")) { Office campaignOffice = this.officeRepository.findOne(Long.valueOf(value)); if (campaignOffice .doesNotHaveAnOfficeInHierarchyWithId(client.getOffice().getId())) { throw new RuntimeException(); } } else { throw new RuntimeException(); } } } String message = this.smsCampaignWritePlatformCommandHandler.compileSmsTemplate( smsCampaign.getMessage(), smsCampaign.getCampaignName(), smsParams); Object mobileNo = smsParams.get("mobileNo"); if (mobileNo != null) { SmsMessage smsMessage = SmsMessage.pendingSms(null, null, client, null, message, mobileNo.toString(), smsCampaign); this.smsMessageRepository.save(smsMessage); Collection<SmsMessage> messages = new ArrayList<>(); messages.add(smsMessage); Map<SmsCampaign, Collection<SmsMessage>> smsDataMap = new HashMap<>(); smsDataMap.put(smsCampaign, messages); this.smsMessageScheduledJobService.sendTriggeredMessages(smsDataMap); } } } } catch (final IOException e) { logger.error("smsParams does not contain the key: " + e.getMessage()); } catch (final RuntimeException e) { logger.debug("Client Office Id and SMS Campaign Office id doesn't match"); } } } } private void sendSmsForSavingsTransaction(final SavingsAccountTransaction savingsTransaction, boolean isDeposit) { String campaignName = isDeposit ? "Savings Deposit" : "Savings Withdrawal"; List<SmsCampaign> smsCampaigns = retrieveSmsCampaigns(campaignName); if (smsCampaigns.size() > 0) { for (SmsCampaign smsCampaign : smsCampaigns) { try { final SavingsAccount savingsAccount = savingsTransaction.getSavingsAccount(); final Client client = savingsAccount.getClient(); HashMap<String, String> campaignParams = new ObjectMapper() .readValue(smsCampaign.getParamValue(), new TypeReference<HashMap<String, String>>() { }); HashMap<String, Object> smsParams = processSavingsTransactionDataForSms(savingsTransaction, client); for (String key : campaignParams.keySet()) { String value = campaignParams.get(key); String spvalue = null; boolean spkeycheck = smsParams.containsKey(key); if (spkeycheck) { spvalue = smsParams.get(key).toString(); } if (spkeycheck && !(value.equals("-1") || spvalue.equals(value))) { if (key.equals("officeId")) { Office campaignOffice = this.officeRepository.findOne(Long.valueOf(value)); if (campaignOffice .doesNotHaveAnOfficeInHierarchyWithId(client.getOffice().getId())) { throw new RuntimeException(); } } else { throw new RuntimeException(); } } } String message = this.smsCampaignWritePlatformCommandHandler .compileSmsTemplate(smsCampaign.getMessage(), smsCampaign.getCampaignName(), smsParams); Object mobileNo = smsParams.get("mobileNo"); if (mobileNo != null) { SmsMessage smsMessage = SmsMessage.pendingSms(null, null, client, null, message, mobileNo.toString(), smsCampaign); this.smsMessageRepository.save(smsMessage); Collection<SmsMessage> messages = new ArrayList<>(); messages.add(smsMessage); Map<SmsCampaign, Collection<SmsMessage>> smsDataMap = new HashMap<>(); smsDataMap.put(smsCampaign, messages); this.smsMessageScheduledJobService.sendTriggeredMessages(smsDataMap); } } catch (final IOException e) { logger.error("smsParams does not contain the key: " + e.getMessage()); } catch (final RuntimeException e) { logger.debug("Client Office Id and SMS Campaign Office id doesn't match"); } } } } private List<SmsCampaign> retrieveSmsCampaigns(String paramValue) { List<SmsCampaign> smsCampaigns = smsCampaignRepository.findActiveSmsCampaigns("%" + paramValue + "%", SmsCampaignTriggerType.TRIGGERED.getValue()); return smsCampaigns; } private HashMap<String, Object> processRepaymentDataForSms(final LoanTransaction loanTransaction, Client groupClient) { HashMap<String, Object> smsParams = new HashMap<String, Object>(); Loan loan = loanTransaction.getLoan(); final Client client; if (loan.isGroupLoan() && groupClient != null) { client = groupClient; } else if (loan.isIndividualLoan()) { client = loan.getClient(); } else { throw new InvalidParameterException(""); } DateTimeFormatter timeFormatter = DateTimeFormat.forPattern("HH:mm"); DateTimeFormatter dateFormatter = DateTimeFormat.forPattern("MMM:d:yyyy"); smsParams.put("id", loanTransaction.getLoan().getClientId()); smsParams.put("firstname", client.getFirstname()); smsParams.put("middlename", client.getMiddlename()); smsParams.put("lastname", client.getLastname()); smsParams.put("FullName", client.getDisplayName()); smsParams.put("mobileNo", client.mobileNo()); smsParams.put("LoanAmount", loan.getPrincpal()); smsParams.put("LoanOutstanding", loanTransaction.getOutstandingLoanBalance()); smsParams.put("loanId", loan.getId()); smsParams.put("LoanAccountId", loan.getAccountNumber()); smsParams.put("officeId", client.getOffice().getId()); if (client.getStaff() != null) { smsParams.put("loanOfficerId", client.getStaff().getId()); } else { smsParams.put("loanOfficerId", -1); } smsParams.put("repaymentAmount", loanTransaction.getAmount(loan.getCurrency())); smsParams.put("RepaymentDate", loanTransaction.getCreatedDateTime().toLocalDate().toString(dateFormatter)); smsParams.put("RepaymentTime", loanTransaction.getCreatedDateTime().toLocalTime().toString(timeFormatter)); if (loanTransaction.getPaymentDetail() != null) { smsParams.put("receiptNumber", loanTransaction.getPaymentDetail().getReceiptNumber()); } else { smsParams.put("receiptNumber", -1); } return smsParams; } private HashMap<String, Object> processSavingsTransactionDataForSms( final SavingsAccountTransaction savingsAccountTransaction, Client client) { // {{savingsId}} {{id}} {{firstname}} {{middlename}} {{lastname}} {{FullName}} {{mobileNo}} {{savingsAccountId}} {{depositAmount}} {{balance}} //transactionDate HashMap<String, Object> smsParams = new HashMap<String, Object>(); SavingsAccount savingsAccount = savingsAccountTransaction.getSavingsAccount(); DateTimeFormatter dateFormatter = DateTimeFormat.forPattern("MMM:d:yyyy"); smsParams.put("clientId", client.getId()); smsParams.put("firstname", client.getFirstname()); smsParams.put("middlename", client.getMiddlename()); smsParams.put("lastname", client.getLastname()); smsParams.put("FullName", client.getDisplayName()); smsParams.put("mobileNo", client.mobileNo()); smsParams.put("savingsId", savingsAccount.getId()); smsParams.put("savingsAccountNo", savingsAccount.getAccountNumber()); smsParams.put("withdrawAmount", savingsAccountTransaction.getAmount(savingsAccount.getCurrency())); smsParams.put("depositAmount", savingsAccountTransaction.getAmount(savingsAccount.getCurrency())); smsParams.put("balance", savingsAccount.getWithdrawableBalance()); smsParams.put("officeId", client.getOffice().getId()); smsParams.put("transactionDate", savingsAccountTransaction.getTransactionLocalDate().toString(dateFormatter)); smsParams.put("savingsTransactionId", savingsAccountTransaction.getId()); if (client.getStaff() != null) { smsParams.put("loanOfficerId", client.getStaff().getId()); } else { smsParams.put("loanOfficerId", -1); } if (savingsAccountTransaction.getPaymentDetail() != null) { smsParams.put("receiptNumber", savingsAccountTransaction.getPaymentDetail().getReceiptNumber()); } else { smsParams.put("receiptNumber", -1); } return smsParams; } private abstract class SmsBusinessEventAdapter implements BusinessEventListner { @Override public void businessEventToBeExecuted(Map<BUSINESS_ENTITY, Object> businessEventEntity) { //Nothing to do } } private class SendSmsOnLoanApproved extends SmsBusinessEventAdapter { @Override public void businessEventWasExecuted( Map<BusinessEventNotificationConstants.BUSINESS_ENTITY, Object> businessEventEntity) { Object entity = businessEventEntity.get(BusinessEventNotificationConstants.BUSINESS_ENTITY.LOAN); if (entity instanceof Loan) { Loan loan = (Loan) entity; notifyAcceptedLoanOwner(loan); } } } private class SendSmsOnLoanRejected extends SmsBusinessEventAdapter { @Override public void businessEventWasExecuted( Map<BusinessEventNotificationConstants.BUSINESS_ENTITY, Object> businessEventEntity) { Object entity = businessEventEntity.get(BusinessEventNotificationConstants.BUSINESS_ENTITY.LOAN); if (entity instanceof Loan) { Loan loan = (Loan) entity; notifyRejectedLoanOwner(loan); } } } private class SendSmsOnLoanRepayment extends SmsBusinessEventAdapter { @Override public void businessEventWasExecuted( Map<BusinessEventNotificationConstants.BUSINESS_ENTITY, Object> businessEventEntity) { Object entity = businessEventEntity .get(BusinessEventNotificationConstants.BUSINESS_ENTITY.LOAN_TRANSACTION); if (entity instanceof LoanTransaction) { LoanTransaction loanTransaction = (LoanTransaction) entity; sendSmsForLoanRepayment(loanTransaction); } } } private class ClientActivatedListener extends SmsBusinessEventAdapter { @Override public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> businessEventEntity) { Object entity = businessEventEntity.get(BusinessEventNotificationConstants.BUSINESS_ENTITY.CLIENT); if (entity instanceof Client) { notifyClientActivated((Client) entity); } } } private class ClientRejectedListener extends SmsBusinessEventAdapter { @Override public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> businessEventEntity) { Object entity = businessEventEntity.get(BusinessEventNotificationConstants.BUSINESS_ENTITY.CLIENT); if (entity instanceof Client) { notifyClientRejected((Client) entity); } } } private class SavingsAccountActivatedListener extends SmsBusinessEventAdapter { @Override public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> businessEventEntity) { Object entity = businessEventEntity.get(BusinessEventNotificationConstants.BUSINESS_ENTITY.SAVING); if (entity instanceof SavingsAccount) { notifySavingsAccountActivated((SavingsAccount) entity); } } } private class SavingsAccountRejectedListener extends SmsBusinessEventAdapter { @Override public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> businessEventEntity) { Object entity = businessEventEntity.get(BusinessEventNotificationConstants.BUSINESS_ENTITY.SAVING); if (entity instanceof SavingsAccount) { notifySavingsAccountRejected((SavingsAccount) entity); } } } private class SavingsAccountTransactionListener extends SmsBusinessEventAdapter { final boolean isDeposit; public SavingsAccountTransactionListener(final boolean isDeposit) { this.isDeposit = isDeposit; } @Override public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> businessEventEntity) { Object entity = businessEventEntity .get(BusinessEventNotificationConstants.BUSINESS_ENTITY.SAVINGS_TRANSACTION); if (entity instanceof SavingsAccountTransaction) { sendSmsForSavingsTransaction((SavingsAccountTransaction) entity, this.isDeposit); } } } /*private abstract class Task implements Runnable { protected final FineractPlatformTenant tenant; protected final String reportName ; private final Object entity ; public Task(final FineractPlatformTenant tenant, final String reportName, final Object entity) { this.tenant = tenant; this.reportName = reportName ; this.entity = entity ; } }*/ }