All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fi.evolver.basics.spring.messaging.sender.FtpSender Maven / Gradle / Ivy

package fi.evolver.basics.spring.messaging.sender;

import static fi.evolver.basics.spring.messaging.util.SendUtils.PROPERTY_CONNECT_TIMEOUT_MS;
import static fi.evolver.basics.spring.messaging.util.SendUtils.PROPERTY_READ_TIMEOUT_MS;
import static fi.evolver.basics.spring.messaging.util.SendUtils.createDataStream;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.zip.GZIPOutputStream;

import org.apache.commons.io.input.TeeInputStream;
import org.apache.commons.io.output.CountingOutputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import fi.evolver.basics.spring.log.MessageLogService;
import fi.evolver.basics.spring.log.entity.MessageLog.Direction;
import fi.evolver.basics.spring.log.entity.MessageLogMetadata;
import fi.evolver.basics.spring.messaging.SendResult;
import fi.evolver.basics.spring.messaging.entity.Message;
import fi.evolver.basics.spring.messaging.util.SendUtils;
import fi.evolver.utils.UriUtils;
import fi.evolver.utils.ftp.ConnectionFactory;
import fi.evolver.utils.ftp.RemoteConnection;
import fi.evolver.utils.stream.FinishingInputStream;


@Component
public class FtpSender implements Sender {
	private static final String PROPERTY_CREATE_MISSING_DIRS = "CreateMissingDirs";
	private static final String PROPERTY_OVERWRITE = "Overwrite";
	private static final String PROPERTY_TEMP_NAME = "TempName";
	private static final String PROPERTY_IDENTITY_FILE = "IdentityFile";


	private final MessageLogService messageLogService;


	@Autowired
	public FtpSender(MessageLogService messageLogService) {
		this.messageLogService = messageLogService;
	}


	@Override
	public SendResult send(Message message, URI uri) {
		String statusCode = "OK";
		String statusMessage = "OK";
		LocalDateTime start = LocalDateTime.now();

		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		CountingOutputStream counter = null;

		URI connectionUri = removeTargetFileName(uri);
		int connectTimeoutMs = message.getMessageTargetConfig().getIntProperty(PROPERTY_CONNECT_TIMEOUT_MS).orElse(10_000);
		int readTimeoutMs = message.getMessageTargetConfig().getIntProperty(PROPERTY_READ_TIMEOUT_MS).orElse(60_000);
		boolean createDirs = message.getMessageTargetConfig().getBooleanProperty(PROPERTY_CREATE_MISSING_DIRS).orElse(false);
		List identityFiles = message.getMessageTargetConfig().getProperty(PROPERTY_IDENTITY_FILE).map(Collections::singletonList).orElse(Collections.emptyList());

		try (InputStream dataStream = createDataStream(message); RemoteConnection connection = ConnectionFactory.connect(connectionUri, connectTimeoutMs, readTimeoutMs, createDirs, identityFiles)) {
			OutputStream out = new GZIPOutputStream(baos);
			counter = new CountingOutputStream(out);

			File targetFile = new File(uri.getPath());
			String tempName = SendUtils.getTagReplacedTargetProperty(message, PROPERTY_TEMP_NAME).orElse(null);
			boolean overwrite = message.getMessageTargetConfig().getBooleanProperty(PROPERTY_OVERWRITE).orElse(false);

			if (createDirs) {
				Optional tempDir = Optional.ofNullable(tempName).map(File::new).map(File::getParent);
				if (tempDir.isPresent())
					connection.mkdirs(tempDir.get());
			}

			try (InputStream in = new FinishingInputStream(new TeeInputStream(dataStream, counter, true))) {
				connection.upload(targetFile.getName(), in, tempName, overwrite);
			}

			return SendResult.success();
		}
		catch (RuntimeException e) {
			statusCode = "UNEXPECTED_ERROR";
			statusMessage = "Unexpected error";
			throw e;
		}
		catch (IOException e) {
			statusCode = "IO_ERROR";
			statusMessage = "Communication problems";
			return SendResult.error("IO ERROR: %s", e.getMessage());
		}
		finally {
			messageLogService.logZippedMessage(
					start,
					message.getMessageType(),
					uri.getScheme(),
					uri.toString(),
					messageLogService.getApplicationName(),
					message.getTargetSystem(),
					Direction.OUTBOUND,
					counter == null ? - 1 : counter.getCount(),
					baos.toByteArray(),
					null,
					0,
					null,
					null,
					statusCode,
					statusMessage,
					convertToMetadataList(message.getMetadata()));
		}
	}


	private static List convertToMetadataList(Map metadata) {
		List result = new ArrayList<>();
		metadata.forEach((k, v) -> result.add(new MessageLogMetadata(k, v)));
		return result;
	}


	private static URI removeTargetFileName(URI uri) {
		try {
			File target = new File(uri.getPath());
			String username = UriUtils.getUserName(uri);
			String password = UriUtils.getPassword(uri);
			return UriUtils.create(uri.getScheme(), username, password, uri.getHost(), target.getParent().replace(File.separatorChar, '/'), null, uri.getFragment());
		}
		catch (URISyntaxException e) {
			throw new IllegalArgumentException("Failed removing target file name from " + uri.getScheme() + " URI", e);
		}
	}


	@Override
	public Set getSupportedProtocols() {
		return Set.of("ftp", "sftp");
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy