/* * Copyright (c) 2005-2011 Grameen Foundation USA * All rights reserved. * * Licensed 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. * * See also http://www.apache.org/licenses/LICENSE-2.0.html for an * explanation of the license and how it is applied. */ package org.mifos.framework.components.batchjobs.helpers; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.joda.time.Days; import org.mifos.accounts.business.AccountBO; import org.mifos.accounts.persistence.LegacyAccountDao; import org.mifos.accounts.savings.business.SavingsBO; import org.mifos.application.holiday.business.Holiday; import org.mifos.application.holiday.persistence.HolidayDao; import org.mifos.application.servicefacade.ApplicationContextProvider; import org.mifos.config.FiscalCalendarRules; import org.mifos.config.GeneralConfig; import org.mifos.customers.business.CustomerAccountBO; import org.mifos.framework.components.batchjobs.SchedulerConstants; import org.mifos.framework.components.batchjobs.TaskHelper; import org.mifos.framework.components.batchjobs.exceptions.BatchJobException; import org.mifos.framework.exceptions.PersistenceException; import org.mifos.framework.hibernate.helper.StaticHibernateUtil; import org.mifos.framework.util.DateTimeService; import org.mifos.schedule.ScheduledDateGeneration; import org.mifos.schedule.internal.HolidayAndWorkingDaysAndMoratoriaScheduledDateGeneration; public class GenerateMeetingsForCustomerAndSavingsHelper extends TaskHelper { private HolidayDao holidayDao = ApplicationContextProvider.getBean(HolidayDao.class); private final LegacyAccountDao legacyAccountDao = ApplicationContextProvider.getBean(LegacyAccountDao.class); private List<Days> workingDays; private Map<Short, List<Holiday>> officeCurrentAndFutureHolidays; public GenerateMeetingsForCustomerAndSavingsHelper() { super(); } @Override public void execute(@SuppressWarnings("unused") final long timeInMillis) throws BatchJobException { workingDays = new FiscalCalendarRules().getWorkingDaysAsJodaTimeDays(); officeCurrentAndFutureHolidays = new HashMap<Short, List<Holiday>>(); long taskStartTime = new DateTimeService().getCurrentDateTime().getMillis(); List<Integer> customerAndSavingsAccountIds = findActiveCustomerAndSavingsAccountIdsThatRequiredMeetingsToBeGenerated(); int accountCount = customerAndSavingsAccountIds.size(); if (accountCount == 0) { return; } List<String> errorList = new ArrayList<String>(); int currentRecordNumber = 0; int outputIntervalForBatchJobs = GeneralConfig.getOutputIntervalForBatchJobs(); int batchSize = GeneralConfig.getBatchSizeForBatchJobs(); // jpw - hardcoded recordCommittingSize to 500 because now only accounts that need more schedules are returned int recordCommittingSize = 500; infoLogBatchParameters(accountCount, outputIntervalForBatchJobs, batchSize, recordCommittingSize); long startTime = new DateTimeService().getCurrentDateTime().getMillis(); Integer currentAccountId = null; int updatedRecordCount = 0; try { StaticHibernateUtil.getSessionTL(); StaticHibernateUtil.startTransaction(); for (Integer accountId : customerAndSavingsAccountIds) { currentRecordNumber++; currentAccountId = accountId; AccountBO accountBO = legacyAccountDao.getAccount(accountId); List<Holiday> currentAndFutureHolidays = getOfficeCurrentAndFutureHolidays(accountBO.getOffice() .getOfficeId()); ScheduledDateGeneration scheduleGenerationStrategy = new HolidayAndWorkingDaysAndMoratoriaScheduledDateGeneration( workingDays, currentAndFutureHolidays); if (accountBO instanceof CustomerAccountBO) { ((CustomerAccountBO) accountBO).generateNextSetOfMeetingDates(scheduleGenerationStrategy); updatedRecordCount++; } else if (accountBO instanceof SavingsBO) { ((SavingsBO) accountBO).generateNextSetOfMeetingDates(workingDays, currentAndFutureHolidays); updatedRecordCount++; } if (currentRecordNumber % batchSize == 0) { StaticHibernateUtil.flushAndClearSession(); getLogger().debug("completed HibernateUtil.flushAndClearSession()"); } if (updatedRecordCount > 0) { if (updatedRecordCount % recordCommittingSize == 0) { StaticHibernateUtil.commitTransaction(); StaticHibernateUtil.getSessionTL(); StaticHibernateUtil.startTransaction(); } } if (currentRecordNumber % outputIntervalForBatchJobs == 0) { long time = System.currentTimeMillis(); String message = "" + currentRecordNumber + " processed, " + (accountCount - currentRecordNumber) + " remaining, " + updatedRecordCount + " updated, batch time: " + (time - startTime) + " ms"; logMessage(message); startTime = time; } } StaticHibernateUtil.commitTransaction(); long time = System.currentTimeMillis(); String message = "" + currentRecordNumber + " processed, " + (accountCount - currentRecordNumber) + " remaining, " + updatedRecordCount + " updated, batch time: " + (time - startTime) + " ms"; logMessage(message); } catch (Exception e) { logMessage("account " + currentAccountId.intValue() + " exception " + e.getMessage()); StaticHibernateUtil.rollbackTransaction(); errorList.add(currentAccountId.toString()); getLogger().error("Unable to generate schedules for account with ID " + currentAccountId, e); } finally { StaticHibernateUtil.closeSession(); } if (errorList.size() > 0) { throw new BatchJobException(SchedulerConstants.FAILURE, errorList); } logMessage("GenerateMeetingsForCustomerAndSavings ran in " + (new DateTimeService().getCurrentDateTime().getMillis() - taskStartTime)); } private void infoLogBatchParameters(int accountCount, int outputIntervalForBatchJobs, int batchSize, int recordCommittingSize) { logMessage("Using parameters:" + "\n OutputIntervalForBatchJobs: " + outputIntervalForBatchJobs + "\n BatchSizeForBatchJobs: " + batchSize + "\n RecordCommittingSizeForBatchJobs: " + recordCommittingSize); String initial_message = "" + accountCount + " accounts to process, results output every " + outputIntervalForBatchJobs + " accounts"; logMessage(initial_message); } private List<Integer> findActiveCustomerAndSavingsAccountIdsThatRequiredMeetingsToBeGenerated() throws BatchJobException { List<Integer> customerAndSavingsAccountIds = new ArrayList<Integer>(); try { long time1 = new DateTimeService().getCurrentDateTime().getMillis(); customerAndSavingsAccountIds = legacyAccountDao .getActiveCustomerAndSavingsAccountIdsForGenerateMeetingTask(); long duration = new DateTimeService().getCurrentDateTime().getMillis() - time1; logMessage("Time to execute the query " + duration + " . Got " + customerAndSavingsAccountIds.size() + " accounts."); } catch (PersistenceException e) { throw new BatchJobException(e); } return customerAndSavingsAccountIds; } private List<Holiday> getOfficeCurrentAndFutureHolidays(Short officeId) { List<Holiday> currentAndFutureHolidays = officeCurrentAndFutureHolidays.get(officeId); if (currentAndFutureHolidays != null) { return currentAndFutureHolidays; } List<Holiday> futureHolidays = holidayDao.findCurrentAndFutureOfficeHolidaysEarliestFirst(officeId); officeCurrentAndFutureHolidays.put(officeId, futureHolidays); return futureHolidays; } private void logMessage(String finalMessage) { System.out.println(finalMessage); getLogger().info(finalMessage); } }