org.mifos.platform.accounting.service.AccountingDataCacheManager.java Source code

Java tutorial

Introduction

Here is the source code for org.mifos.platform.accounting.service.AccountingDataCacheManager.java

Source

/*
 * 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.platform.accounting.service;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.StringTokenizer;

import org.apache.commons.io.FileUtils;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.mifos.framework.util.ConfigurationLocator;
import org.mifos.platform.accounting.AccountingDto;
import org.mifos.platform.accounting.AccountingRuntimeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class AccountingDataCacheManager {

    private static final Logger LOGGER = LoggerFactory.getLogger(AccountingDataCacheManager.class);

    // hardcoded FIXME there should be a common way of sharing application wide constants across modules
    private static final int DIGITS_BEFORE_DECIMAL = 14;

    private static final String EXPORT_FILENAME_PREFIX = "Mifos Accounting Export ";

    private String accountingDataPath;
    private Integer digitsAfterDecimal;

    public final List<AccountingDto> getExportDetails(String fileName) {

        String accountingDataLocation = getAccoutingDataCachePath();
        File file = new File(accountingDataLocation + fileName);
        return accountingDataFromCache(file);
    }

    public List<AccountingDto> accountingDataFromCache(File file) {
        BufferedReader br;
        try {
            br = new BufferedReader(new FileReader(file));
        } catch (FileNotFoundException e) {
            LOGGER.error(file.toString(), e);
            throw new AccountingRuntimeException(file.toString(), e);
        }
        String line = null;

        // skip first line
        try {
            br.readLine();
        } catch (IOException e) {
            LOGGER.error("skipping header line", e);
            throw new AccountingRuntimeException("skipping header line", e);
        }

        List<AccountingDto> accountingData = new ArrayList<AccountingDto>();

        try {
            while ((line = br.readLine()) != null) {
                accountingData.add(parseLine(line));
            }
            br.close();
        } catch (IOException e) {
            throw new AccountingRuntimeException("reading line" + line, e);
        }

        return accountingData;
    }

    private String getAccoutingDataCachePath() {
        if (accountingDataPath == null) {
            ConfigurationLocator configurationLocator = new ConfigurationLocator();
            accountingDataPath = configurationLocator.getConfigurationDirectory() + "/accounting/data/";
        }
        File path = new File(accountingDataPath);
        if (!(path.exists() && path.isDirectory())) {
            path.mkdirs();
        }
        return accountingDataPath;
    }

    public final Boolean deleteCacheDir() {
        try {
            FileUtils.deleteDirectory(new File(getAccoutingDataCachePath()));
        } catch (IOException e) {
            LOGGER.error(e.getMessage(), e);
            return false;
        }
        return true;
    }

    private int getDigitsAfterDecimal() {
        if (digitsAfterDecimal != null) {
            // Already read, avoid reading again to reduce processing
            return digitsAfterDecimal;
        }
        ConfigurationLocator configurationLocator = new ConfigurationLocator();
        String customApplicationPropertyFile = configurationLocator.getConfigurationDirectory()
                + "/applicationConfiguration.custom.properties";
        File appConfigFile = new File(customApplicationPropertyFile);
        Properties properties = new Properties();
        if (appConfigFile.exists() && appConfigFile.isFile()) {
            try {
                properties.load(new FileReader(appConfigFile));
            } catch (Exception e) {
                LOGGER.error(e.getMessage(), e);
            }
        } else {
            // FIXME hardcoded default value, using property file only for custom value
            // There should be a way to read application properties across modules
            digitsAfterDecimal = 1;
        }
        digitsAfterDecimal = Integer.parseInt(properties.getProperty("AccountingRules.DigitsAfterDecimal", "1"));
        return digitsAfterDecimal;
    }

    protected final void setAccoutingDataCachePath(String path) {
        accountingDataPath = path;
    }

    private AccountingDto parseLine(String line) {
        StringTokenizer st = new StringTokenizer(line, ";");
        String branchname = st.nextToken().trim();
        String voucherdate = st.nextToken().trim();
        String vouchertype = st.nextToken().trim();
        String glcode = st.nextToken().trim();
        String glname = st.nextToken().trim();
        String debit = parseNumber(st.nextToken().trim());
        String credit = parseNumber(st.nextToken().trim());
        return new AccountingDto(branchname, voucherdate, vouchertype, glcode, glname, debit, credit);
    }

    private String parseNumber(String number) {
        // FIXME should use this from common util
        StringBuilder pattern = new StringBuilder();
        DecimalFormat decimalFormat = (DecimalFormat) DecimalFormat.getCurrencyInstance(Locale.ENGLISH);
        for (Short i = 0; i < DIGITS_BEFORE_DECIMAL; i++) {
            pattern.append('#');
        }
        pattern.append(decimalFormat.getDecimalFormatSymbols().getDecimalSeparator());
        for (short i = 0; i < getDigitsAfterDecimal(); i++) {
            pattern.append('#');
        }
        decimalFormat.applyLocalizedPattern(pattern.toString());
        decimalFormat.setDecimalSeparatorAlwaysShown(false);
        decimalFormat.setMinimumFractionDigits(getDigitsAfterDecimal());
        return decimalFormat.format(Double.parseDouble(number));
    }

    public final boolean isAccountingDataAlreadyInCache(String fileName) {
        return new File(getAccoutingDataCachePath() + fileName).isFile();
    }

    public final void writeAccountingDataToCache(List<AccountingDto> accountingData, String cacheFileName) {
        File file = new File(getAccoutingDataCachePath() + cacheFileName);
        PrintWriter out = null;
        try {
            out = new PrintWriter(file);
        } catch (FileNotFoundException e) {
            LOGGER.error(file.toString(), e);
            throw new AccountingRuntimeException(file.toString(), e);
        }
        out.println("branchname;voucherdate;vouchertype;glcode;glname;debit;credit");
        for (AccountingDto instance : accountingData) {
            out.println(instance.toString());
        }
        out.flush();
        out.close();
    }

    public final String getCacheFileName(LocalDate startDate, LocalDate endDate) {
        return new StringBuffer().append(startDate).append(" to ").append(endDate).toString();
    }

    public final String getTallyOutputFileName(LocalDate startDate, LocalDate endDate) {
        return new StringBuffer().append(getExportFileName(startDate, endDate)).append(".xml").toString();
    }

    public final String getExportFileName(LocalDate startDate, LocalDate endDate) {
        return new StringBuffer().append(EXPORT_FILENAME_PREFIX).append(getCacheFileName(startDate, endDate))
                .toString();
    }

    public final ExportFileInfo getExportFileInfoFromCache(LocalDate startDate, LocalDate endDate) {
        String fileName = getCacheFileName(startDate, endDate);
        File export = new File(getAccoutingDataCachePath() + "/" + fileName);
        return getExportFileInfo(export);
    }

    public final List<ExportFileInfo> getGeneratedExports() {
        List<ExportFileInfo> info = new ArrayList<ExportFileInfo>();
        File directory = new File(getAccoutingDataCachePath());

        for (File file : directory.listFiles()) {
            info.add(getExportFileInfo(file));
        }
        return info;
    }

    protected ExportFileInfo getExportFileInfo(File file) {
        String startDate = file.getName().split(" to ")[0];
        String endDate = file.getName().split(" to ")[1];
        String fileName = new StringBuffer().append(EXPORT_FILENAME_PREFIX).append(file.getName()).toString();
        String lastModified = new DateTime(file.lastModified()).toString("yyyy-MMM-dd HH:mm z");
        Boolean existInCache = true;
        ExportFileInfo export = new ExportFileInfo(lastModified, fileName, startDate, endDate, existInCache);
        return export;
    }

}