/*
* This program is part of the OpenLMIS logistics management information system platform software.
* Copyright © 2013 VillageReach
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License along with this program. If not, see http://www.gnu.org/licenses. For additional information contact info@OpenLMIS.org.
*/
package org.openlmis.order.task;
import org.apache.camel.CamelExecutionException;
import org.apache.camel.FailedToCreateProducerException;
import org.apache.log4j.Logger;
import org.openlmis.core.domain.FacilityFtpDetails;
import org.openlmis.core.domain.SupplyLine;
import org.openlmis.core.service.ConfigurationSettingService;
import org.openlmis.core.service.FacilityFtpDetailsService;
import org.openlmis.core.service.SupplyLineService;
import org.openlmis.order.domain.Order;
import org.openlmis.order.domain.OrderStatus;
import org.openlmis.order.dto.OrderFileTemplateDTO;
import org.openlmis.order.helper.OrderCsvHelper;
import org.openlmis.order.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.FileWriter;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.openlmis.order.domain.OrderStatus.RELEASED;
import static org.openlmis.order.domain.OrderStatus.TRANSFER_FAILED;
/**
* Exposes the services for processing orders, sending their order files to respective ftp locations.
*/
@Component
public class OrderFtpTask {
@Autowired
private ConfigurationSettingService configurationSettingService;
@Autowired
private SupplyLineService supplyLineService;
@Autowired
private FacilityFtpDetailsService facilityFtpDetailsService;
@Autowired
private OrderService orderService;
@Autowired
private OrderCsvHelper orderCsvHelper;
@Autowired
private OrderFtpSender ftpSender;
@Value("${order.ftp.local.directory}")
String localFileDirectory;
Boolean sendFtp;
private void initiateSettings(){
sendFtp = configurationSettingService.getBoolValue("USE_FTP_TO_SEND_ORDERS");
localFileDirectory = configurationSettingService.getConfigurationStringValue("LOCAL_ORDER_EXPORT_DIRECTORY");
}
private static Logger logger = Logger.getLogger(OrderFtpTask.class);
private static String CONNECTION_REFUSED = "Connection refused";
private static String CONNECTION_REFUSED_TIMEOUT = "connect timed out";
private static String LOGIN_INCORRECT = "Login incorrect";
private static String PERMISSION_DENIED = "Error writing file";
private static String CONNECTION_REFUSED_COMMENT = "order.ftpComment.connection.refused";
private static String LOGIN_INCORRECT_COMMENT = "order.ftpComment.incorrect.login";
private static String PERMISSION_DENIED_COMMENT = "order.ftpComment.permission.denied";
public static String FTP_CREDENTIAL_MISSING_COMMENT = "order.ftpComment.ftpcredential.missing";
public void processOrder(@Payload List<Order> orders) {
initiateSettings();
for (Order order : orders) {
order = orderService.getOrder(order.getId());
SupplyLine supplyLine = order.getSupplyLine();
supplyLine = supplyLineService.getById(supplyLine.getId());
FacilityFtpDetails supplyingFacilityFtpDetails = facilityFtpDetailsService.getByFacilityId(supplyLine.getSupplyingFacility());
if (sendFtp && supplyingFacilityFtpDetails == null) {
updateOrder(order, TRANSFER_FAILED, FTP_CREDENTIAL_MISSING_COMMENT);
continue;
}
OrderFileTemplateDTO orderFileTemplateDTO = orderService.getOrderFileTemplateDTO();
String fileName = orderFileTemplateDTO.getOrderConfiguration().getFilePrefix() + order.getId() + ".csv";
File localDirectory = new File(localFileDirectory);
if (!localDirectory.exists()) {
localDirectory.mkdir();
}
File file = new File(localFileDirectory + System.getProperty("file.separator") + fileName);
try (FileWriter fileWriter = new FileWriter(file)) {
orderCsvHelper.writeCsvFile(order, orderFileTemplateDTO, fileWriter);
fileWriter.flush();
if(sendFtp) {
ftpSender.sendFile(supplyingFacilityFtpDetails, file);
}
updateOrder(order, RELEASED, null);
} catch (FailedToCreateProducerException producerException) {
updateOrder(order, TRANSFER_FAILED, CONNECTION_REFUSED_COMMENT);
} catch (CamelExecutionException camelException) {
handleException(camelException, order);
} catch (Exception e) {
logger.error("Error in ftp of order file", e);
updateOrder(order, TRANSFER_FAILED, null);
} finally {
if(sendFtp) {
file.delete();
}
}
}
}
private void handleException(CamelExecutionException camelException, Order order) {
logger.error("Error in ftp of order file", camelException);
if (!(updateOrderForException(CONNECTION_REFUSED_TIMEOUT, camelException, order, CONNECTION_REFUSED_COMMENT) ||
updateOrderForException(CONNECTION_REFUSED, camelException, order, CONNECTION_REFUSED_COMMENT) ||
updateOrderForException(LOGIN_INCORRECT, camelException, order, LOGIN_INCORRECT_COMMENT) ||
updateOrderForException(PERMISSION_DENIED, camelException, order, PERMISSION_DENIED_COMMENT))) {
order.setStatus(TRANSFER_FAILED);
order.setFtpComment(null);
}
orderService.updateOrderStatus(order);
}
private boolean updateOrderForException(String error, Exception exception, Order order, String ftpComment) {
Pattern pattern = Pattern.compile(error);
Matcher matcher = pattern.matcher(exception.getCause().getMessage());
if (matcher.find()) {
order.setStatus(TRANSFER_FAILED);
order.setFtpComment(ftpComment);
return true;
}
return false;
}
private void updateOrder(Order order, OrderStatus status, String ftpComment) {
order.setStatus(status);
order.setFtpComment(ftpComment);
orderService.updateOrderStatus(order);
}
}