O documento descreve como substituir a classe de solicitação de mensagem padrão do conector SFTP no Mule para implementar lógica personalizada de processamento de arquivos em ordem. Isso é feito criando classes personalizadas que substituem as classes utilizadas pelo conector para retornar os arquivos em uma ordem específica antes de processá-los.
1. Substituindo o Request Message no Mule
Ao trabalhar com os conectores de SFTP / FTP em Mule, pode ser
necessário para substituir o conector, a fim de implementar a sua lógica
personalizada. Isto pode ser útil quando a ordem de arquivos a serem
processados é importante, por exemplo. Por exemplo, considere que, em
seu caminho de arquivo de alguns ficheiros são ordenados usando um
exemplo chave 'File_01.txt' e 'file_02.txt', e você deseja consumir arquivos
de forma incremental ou seja, 'file_01.txt' deve ser processado antes
‘file_02.txt’.
Implementando a lógica acima quando o endpoint SFTP funciona como um
ponto de extremidade de entrada é bastante simples. Tudo que você precisa
fazer é substituir o receptor da mensagem sobre o conector do SFTP com o
seu código personalizado.
<sftp:connector name="SFTP" validateConnections="true"
doc:name="SFTP-Sorted"
archiveDir="${sftp.jdeArchiveFilePath}"
keepFileOnError="true"
preferredAuthenticationMethods="publickey,password,keyboard-
interactive">
<service-overrides
messageReceiver="com.ricston.NewSftpReceiver"/>
</sftp:connector>
Por outro lado, quando o conector é chamada através de um ponto de
extremidade de quartzo ou através do módulo solicitante o receptor da
mensagem não será chamada, em vez do conector irá usar o solicitador de
mensagem para recuperar o arquivo. Por esta razão, a substituição de
serviço não pode ser utilizado, uma vez que não fornece uma maneira para
substituir o solicitante. Neste post nós fornecemos um exemplo de trabalho
de como isso pode ser feito.
Uma maneira fácil de alcançar nosso objetivo é substituir as classes usadas
pelo conector de SFTP. Para verificar exatamente quais classes estão sendo
usados, vá para 'sftp.properties' encontrada no pote de mula-transport-sftp
que vem com a distribuição mula que você está usando. Uma das
propriedades listadas neste arquivo é o 'requester.factory ", que aponta para
a classe' org.mule.transport.sftp.SftpMessageRequesterFactory '.
2. Depois de analisar esta classe e as classes faz referência, você deve
observar que o método dos getAvailableFiles 'está sendo usado para
recuperar a lista de todos os arquivos presentes no diretório especificado; e
isso é exatamente o método que deseja usar para retornar a lista dos
arquivos ordenados.
Isto é bastante fácil de fazer; criamos nosso costume
SftpReceiverRequesterUtil que se estende 'SftpReceiverRequesterUtil' e
substituir os getAvailableFiles () para incluir a lógica de classificação e
retornar o primeiro arquivo na lista.
package com.ricston.requester;
import java.util.Arrays;
import org.mule.api.endpoint.ImmutableEndpoint;
import org.mule.transport.sftp.SftpReceiverRequesterUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SortedSftpReceiverRequesterUtil extends
SftpReceiverRequesterUtil {
private static final Logger logger = LoggerFactory
.getLogger(SortedSftpReceiverRequesterUtil.class);
public SortedSftpReceiverRequesterUtil(ImmutableEndpoint
endpoint) {
super(endpoint);
}
3. @Override
public String[] getAvailableFiles(boolean onlyGetTheFirstOne)
throws Exception {
String[] availableFiles = super.getAvailableFiles(false);
sortFiles(availableFiles);
// Return first file in list only
String[] firstFile = new String[1];
if (availableFiles.length > 1) {
firstFile[0] = availableFiles[0];
return firstFile;
} else {
return availableFiles;
}
}
private void sortFiles(String availableFiles[]) {
int n = availableFiles.length;
int k;
for (int m = n; m >= 0; m--) {
for (int i = 0; i < m - 1; i++) {
k = i + 1;
int firstBatchNumber =
getBatchNumber(availableFiles[i]);
int secondBatchNumber =
getBatchNumber(availableFiles[k]);
if (firstBatchNumber >
secondBatchNumber) {
swapFiles(i, k, availableFiles);
}
}
}
}
private int getBatchNumber(String fileName) {
return Integer.parseInt(fileName.substring(
fileName.lastIndexOf("_") + 1,
fileName.lastIndexOf(".")));
4. }
private void swapFiles(int i, int j, String[] availableFiles) {
String temp;
temp = availableFiles[i];
availableFiles[i] = availableFiles[j];
availableFiles[j] = temp;
}
}
A fim de tornar o 'SftpMessageRequester' usar o nosso código, nós criamos
nosso SftpMessageRequester personalizado que se refere ao nosso costume
'SftpReceiverRequesterUtil' criado na etapa anterior. Esta classe terá o
mesmo comportamento como o "SftpMessageRequester ', mas em vez de
instanciar' SftpReceiverRequesterUtil ', ele irá instanciar'
SortedSftpReceiverRequesterUtil '.
package com.ricston.requester;
import java.io.InputStream;
import org.mule.api.MuleMessage;
import org.mule.api.endpoint.InboundEndpoint;
import org.mule.api.transport.PropertyScope;
import org.mule.transport.AbstractMessageRequester;
import org.mule.transport.sftp.SftpConnector;
import org.mule.transport.sftp.notification.SftpNotifier;
public class CustomSftpMessageRequester extends
AbstractMessageRequester {
private SortedSftpReceiverRequesterUtil sftpRRUtil = null;
public CustomSftpMessageRequester(InboundEndpoint endpoint)
{
super(endpoint);
sftpRRUtil = new
SortedSftpReceiverRequesterUtil(endpoint);
5. }
@Override
protected MuleMessage doRequest(long timeout) throws Exception
{
String[] files = sftpRRUtil.getAvailableFiles(true);
if (files.length == 0)
return null;
String path = files[0];
// TODO. ML FIX. Can't we figure out the current service
(for
// logging/audit
// purpose)???
SftpNotifier notifier = new SftpNotifier((SftpConnector)
connector,
createNullMuleMessage(), endpoint,
endpoint.getName());
InputStream inputStream = sftpRRUtil.retrieveFile(path,
notifier);
logger.debug("Routing file: " + path);
MuleMessage message =
createMuleMessage(inputStream);
message.setProperty(SftpConnector.PROPERTY_ORIGINAL_FIL
ENAME, path,
PropertyScope.INBOUND);
// Now we can update the notifier with the message
notifier.setMessage(message);
return message;
}
}
Finalmente, queremos criar uma nova classe de fábrica com o mesmo
comportamento como 'SftpMessageRequesterFactory ", mas em vez de
6. retornar" SftpMessageRequester', ele irá retornar
'CustomSftpMessageRequester'.
package com.ricston.requester;
import org.mule.api.MuleException;
import org.mule.api.endpoint.InboundEndpoint;
import org.mule.api.transport.MessageRequester;
import org.mule.transport.AbstractMessageRequesterFactory;
public class CustomSftpMessageRequesterFactory extends
AbstractMessageRequesterFactory
{
public MessageRequester create(InboundEndpoint endpoint) throws
MuleException
{
return new CustomSftpMessageRequester(endpoint);
}
}
Agora que estamos a fazer com o código, queremos substituir o conector de
SFTP para que ele faz uso desta classe de fábrica recém-criada. Para fazer
isso, usamos mola para substituir a propriedade 'requester.factory'
encontrado em sftp.properties.
<sftp:connector name="SFTP" validateConnections="true"
doc:name="SFTP-Sorted"
archiveDir="/archiveDir"
keepFileOnError="true"
preferredAuthenticationMethods="publickey,password,keyboard-
interactive">
<spring:property name="serviceOverrides">
<spring:map>
<spring:entry key="requester.factory"
value="com.ricston.requester.CustomSftpMessageRequesterFactor
y" />
</spring:map>
</spring:property>
</sftp:connector>
7. Isso é tudo o que você precisa fazer para processar arquivos em ordem.
Para testar isso, coloque dois arquivos ou mais em um diretório de sua
escolha, e apontar o endpoint SFTP para este diretório. Note-se que para
este trabalho o nome do arquivo deve terminar com; _number.extension
(verifique getBatchNumber () in SortedSftpReceiverRequesterUtil.java).
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:vm="http://www.mulesoft.org/schema/mule/vm"
xmlns:http="http://www.mulesoft.org/schema/mule/http"
xmlns:mulerequester="http://www.mulesoft.org/schema/mule/mule
requester"
xmlns:file="http://www.mulesoft.org/schema/mule/file"
xmlns:sftp="http://www.mulesoft.org/schema/mule/sftp"
xmlns="http://www.mulesoft.org/schema/mule/core"
xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:spring="http://www.springframework.org/schema/beans"
version="EE-3.6.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.mulesoft.org/schema/mule/sftp
http://www.mulesoft.org/schema/mule/sftp/current/mule-sftp.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core
http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/file
http://www.mulesoft.org/schema/mule/file/current/mule-file.xsd
http://www.mulesoft.org/schema/mule/http
http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/mulerequester
http://www.mulesoft.org/schema/mule/mulerequester/current/mule-
mulerequester.xsd
http://www.mulesoft.org/schema/mule/vm
http://www.mulesoft.org/schema/mule/vm/current/mule-vm.xsd">
<sftp:connector name="SFTP" validateConnections="true"
doc:name="SFTP-Sorted"
archiveDir="/archiveDir"