/* * 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.application.importexport.struts.action; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.io.IOUtils; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.upload.FormFile; import org.mifos.application.importexport.struts.actionforms.ImportTransactionsActionForm; import org.mifos.application.servicefacade.ListItem; import org.mifos.dto.domain.ParseResultDto; import org.mifos.framework.business.AbstractBusinessObject; import org.mifos.framework.business.service.BusinessService; import org.mifos.framework.exceptions.ServiceException; import org.mifos.framework.struts.action.BaseAction; import org.mifos.framework.util.helpers.Money; import org.mifos.security.util.UserContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This class takes the {@link ImportTransactionsActionForm} and retrieves file * with details transactions received from a third party (mostly a bank) and * import the details to collection sheet entry module */ public class ImportTransactionsAction extends BaseAction { private static final Logger logger = LoggerFactory.getLogger(ImportTransactionsAction.class); private static final String IMPORT_TEMPORARY_FILENAME = "importTemporaryFilename"; private static final String IMPORT_PLUGIN_CLASSNAME = "importPluginClassname"; public static final String SESSION_ATTRIBUTE_LOG = "importTransactionLog"; public static final String SESSION_ATTRIBUTE_LOG_FILENAME = "importTransactionLogFilename"; public ActionForward load(ActionMapping mapping, ActionForm form, HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) throws Exception { final ImportTransactionsActionForm importTransactionsForm = (ImportTransactionsActionForm) form; importTransactionsForm.clear(); clearOurSessionVariables(request.getSession()); final List<ListItem<String>> importPlugins = this.importTransactionsServiceFacade.retrieveImportPlugins(); request.setAttribute("importPlugins", importPlugins); return mapping.findForward("import_load"); } public ActionForward upload(ActionMapping mapping, ActionForm form, HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) throws Exception { final ImportTransactionsActionForm importTransactionsForm = (ImportTransactionsActionForm) form; final FormFile importTransactionsFile = importTransactionsForm.getImportTransactionsFile(); final String importPluginClassname = importTransactionsForm.getImportPluginName(); request.getSession().setAttribute(IMPORT_PLUGIN_CLASSNAME, importPluginClassname); final InputStream stream = importTransactionsFile.getInputStream(); final String tempFilename = saveImportAsTemporaryFile(importTransactionsFile.getInputStream()); request.getSession().setAttribute(IMPORT_TEMPORARY_FILENAME, tempFilename); final ParseResultDto importResult = this.importTransactionsServiceFacade.parseImportTransactions(importPluginClassname, importTransactionsFile.getInputStream()); final List<String> errorsForDisplay = new ArrayList<String>(); if (!importResult.getParseErrors().isEmpty()) { errorsForDisplay.addAll(importResult.getParseErrors()); } int numberRowSuccessfullyParsed = importResult.getNumberRowSuccessfullyParsed(); if(numberRowSuccessfullyParsed == -1) { numberRowSuccessfullyParsed = importResult.getSuccessfullyParsedPayments().size(); } boolean submitButtonDisabled = false; if (numberRowSuccessfullyParsed == 0) { submitButtonDisabled = true; } if (importResult.isAmountInformationFilled() && importResult.isExtraRowInformationFilled()) { request.setAttribute("isExtraInformationFilled", true); request.setAttribute("numberOfErrorRows", importResult.getNumberOfErrorRows()); request.setAttribute("numberOfIgnoredRows", importResult.getNumberOfIgnoredRows()); request.setAttribute("numberOfReadRows", importResult.getNumberOfReadRows()); request.setAttribute("totalAmountOfTransactionsImported", new Money(Money.getDefaultCurrency(), importResult.getTotalAmountOfTransactionsImported()).toString()); request.setAttribute("totalAmountOfTransactionsWithError", new Money(Money.getDefaultCurrency(), importResult.getTotalAmountOfTransactionsWithError()).toString()); request.setAttribute("totalAmountOfDisbursementsTransactionsImported", new Money(Money.getDefaultCurrency(), importResult.getTotalAmountOfDisbursementsImported().toString())); request.getSession().setAttribute(SESSION_ATTRIBUTE_LOG, importResult.getStatusLogFile().getBytes()); request.getSession().setAttribute(SESSION_ATTRIBUTE_LOG_FILENAME, statusLogfileName(importTransactionsFile.getFileName())); } else { request.setAttribute("isExtraInformationFilled", false); } request.setAttribute("importTransactionsErrors", errorsForDisplay); request.setAttribute("numSuccessfulRows", numberRowSuccessfullyParsed); request.setAttribute("submitButtonDisabled", submitButtonDisabled); request.setAttribute("numberOfOverpayments", importResult.getNumberOfOverpayments()); stream.close(); importTransactionsFile.destroy(); return mapping.findForward("import_results"); } /** * This will fail if we ever cluster Mifos dynamic Web requests. */ private String saveImportAsTemporaryFile(InputStream input) throws IOException { File tempFile = File.createTempFile(this.getClass().getSimpleName(), null); FileOutputStream out = new FileOutputStream(tempFile); BufferedInputStream in = new BufferedInputStream(input); byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } in.close(); out.close(); return tempFile.getCanonicalPath(); } public ActionForward confirm(ActionMapping mapping, ActionForm form, HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) throws Exception { final String tempFilename = (String) request.getSession().getAttribute(IMPORT_TEMPORARY_FILENAME); final String importPluginClassname = (String) request.getSession().getAttribute(IMPORT_PLUGIN_CLASSNAME); final ImportTransactionsActionForm importTransactionsForm = (ImportTransactionsActionForm) form; final String importTransactionsFileName = importTransactionsForm.getImportTransactionsFile().getFileName(); final ParseResultDto importResult = this.importTransactionsServiceFacade.confirmImport(importPluginClassname, tempFilename); if (null != importResult.getParseErrors() && !importResult.getParseErrors().isEmpty()) { for (String error : importResult.getParseErrors()) { logger.warn(importTransactionsFileName + ": " + error); } } this.importTransactionsServiceFacade.saveImportedFileName(importTransactionsFileName, importPluginClassname, importResult.getTrxIdsToUndo()); logger.info(importResult.getNumberRowSuccessfullyParsed() + " transaction(s) imported from "+ importTransactionsFileName + "."); return mapping.findForward("import_confirm"); } public ActionForward downloadLog(@SuppressWarnings("unused") ActionMapping mapping, @SuppressWarnings("unused") ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { byte[] fileContents = (byte[]) request.getSession().getAttribute(ImportTransactionsAction.SESSION_ATTRIBUTE_LOG); String fileName = (String) request.getSession().getAttribute(ImportTransactionsAction.SESSION_ATTRIBUTE_LOG_FILENAME); response.setHeader("Content-disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8")); response.setContentType("text/plain"); IOUtils.copy(new ByteArrayInputStream(fileContents), response.getOutputStream()); return null; } private String statusLogfileName(String uploadedFilename) { if (uploadedFilename.contains(".")) { return uploadedFilename.split("\\.")[0] + "-log.txt"; } return uploadedFilename + "-log.txt"; } /** * Used to remove our (this action's) temporaries after use to keep them * from accumulating in the session. This probably breaks the "back" button. * Using hidden form fields to persist temporaries might be more * user-friendly. */ private void clearOurSessionVariables(HttpSession session) { session.removeAttribute(IMPORT_TEMPORARY_FILENAME); session.removeAttribute(IMPORT_PLUGIN_CLASSNAME); session.removeAttribute(SESSION_ATTRIBUTE_LOG); session.removeAttribute(SESSION_ATTRIBUTE_LOG_FILENAME); } @Override protected BusinessService getService() throws ServiceException { return new DummyImportTransactionService(); } class DummyImportTransactionService implements BusinessService { @Override public AbstractBusinessObject getBusinessObject(@SuppressWarnings("unused") final UserContext userContext) { return null; } } }