SMB サポート

Spring Integration は、SMB を使用したファイル転送操作をサポートします。

サーバーメッセージブロック [Wikipedia] (英語) (SMB) は、共有ファイルサーバーにファイルを転送できるシンプルなネットワークプロトコルです。

この依存関係をプロジェクトに含める必要があります。

<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-smb</artifactId>
    <version>6.4.1</version>
</dependency>
compile "org.springframework.integration:spring-integration-smb:6.4.1"

概要

CIFS/SMB ネットワークプロトコルの Java 実装として、Java CIFS [GitHub] (英語) クライアントライブラリが選択されました。その SmbFile 抽象化は、SmbSessionSmbRemoteFileTemplate などの Spring Integration 「リモートファイル」基盤に単純にラップされます。

SMB チャネルアダプターとサポートクラスの実装は、(S)FTP または AWS S3 プロトコルの既存のコンポーネントと完全に似ています。これらのコンポーネントに精通していれば、使用するのは非常に簡単です。

Spring Integration は、受信チャネルアダプター、送信チャネルアダプター、および送信ゲートウェイの 3 つのクライアント側エンドポイントを提供することにより、SMB を介したファイルの送受信をサポートします。また、これらのクライアントコンポーネントを定義するための便利な名前空間ベースの構成オプションも提供します。

SMB 名前空間を使用するには、XML ファイルのヘッダーに次を追加します。

xmlns:int-smb="http://www.springframework.org/schema/integration/smb"
xsi:schemaLocation="http://www.springframework.org/schema/integration/smb
    https://www.springframework.org/schema/integration/smb/spring-integration-smb.xsd"

SMB セッションファクトリ

SMB アダプターを構成する前に、SMB セッションファクトリを構成する必要があります。次の例に示すように、通常の Bean 定義を使用して SMB セッションファクトリを構成できます。

SmbSessionFactory は、最小 / 最大バージョンで SMB プロトコルを設定するオプションを公開します。例: SMB 2.1 の最小バージョンと SMB 3.1.1 の最大バージョンをサポートします。

@Bean
public SmbSessionFactory smbSessionFactory() {
    SmbSessionFactory smbSession = new SmbSessionFactory();
    smbSession.setHost("myHost");
    smbSession.setPort(445);
    smbSession.setDomain("myDomain");
    smbSession.setUsername("myUser");
    smbSession.setPassword("myPassword");
    smbSession.setShareAndDir("myShareAndDir");
    smbSession.setSmbMinVersion(DialectVersion.SMB210);
    smbSession.setSmbMaxVersion(DialectVersion.SMB311);
    return smbSession;
}

SmbSessionFactory はカスタム jcifs.CIFSContext で初期化できます。

SMB プロトコルの最小 / 最大バージョンの設定は、jcifs.CIFSContext の実装で行う必要があります。
@Bean
public SmbSessionFactory smbSessionFactory() {
    SmbSessionFactory smbSession = new SmbSessionFactory(new MyCIFSContext());
    smbSession.setHost("myHost");
    smbSession.setPort(445);
    smbSession.setDomain("myDomain");
    smbSession.setUsername("myUser");
    smbSession.setPassword("myPassword");
    smbSession.setShareAndDir("myShareAndDir");
    return smbSession;
}

SMB 受信チャネルアダプター

SMB ファイルをローカルにダウンロードするために、SmbInboundFileSynchronizingMessageSource が提供されています。SmbInboundFileSynchronizer インジェクションを必要とする AbstractInboundFileSynchronizingMessageSource の単純な拡張です。リモートファイルをフィルタリングするために、既存の FileListFilter 実装を引き続き使用できますが、特定の SmbRegexPatternFileListFilter および SmbSimplePatternFileListFilter が提供されています。

@Bean
public SmbInboundFileSynchronizer smbInboundFileSynchronizer() {
    SmbInboundFileSynchronizer fileSynchronizer =
        new SmbInboundFileSynchronizer(smbSessionFactory());
    fileSynchronizer.setFilter(compositeFileListFilter());
    fileSynchronizer.setRemoteDirectory("mySharedDirectoryPath");
    fileSynchronizer.setDeleteRemoteFiles(true);
    return fileSynchronizer;
}

@Bean
public CompositeFileListFilter<SmbFile> compositeFileListFilter() {
    CompositeFileListFilter<SmbFile> filters = new CompositeFileListFilter<>();
    filters.addFilter(new SmbRegexPatternFileListFilter("^(?i).+((\\.txt))$"));
    return filters;
}

@Bean
public MessageChannel smbFileInputChannel() {
    return new DirectChannel();
}

@Bean
@InboundChannelAdapter(value = "smbFileInputChannel",
                       poller = @Poller(fixedDelay = "2000"))
public MessageSource<File> smbMessageSource() {
    SmbInboundFileSynchronizingMessageSource messageSource =
        new SmbInboundFileSynchronizingMessageSource(smbInboundFileSynchronizer());
    messageSource.setLocalDirectory(new File("myLocalDirectoryPath"));
    messageSource.setAutoCreateLocalDirectory(true);
    return messageSource;
}

XML 構成用に、<int-smb:inbound-channel-adapter> コンポーネントが提供されています。

バージョン 6.2 以降では、SmbLastModifiedFileListFilter を使用して、最終変更戦略に基づいて SMB ファイルをフィルタリングできます。このフィルターは age プロパティを使用して構成でき、この値よりも古いファイルのみがフィルターを通過するようになります。デフォルトの経過時間は 60 秒ですが、(ネットワーク障害などによる) 早期にファイルが選択されることを避けるために、十分な長さを選択する必要があります。詳細については、Javadoc を参照してください。

Java DSL を使用した構成

次の Spring Boot アプリケーションは、Java DSL で受信アダプターを構成する方法の例を示しています。

@SpringBootApplication
public class SmbJavaApplication {

    public static void main(String[] args) {
        new SpringApplicationBuilder(SmbJavaApplication.class)
            .web(false)
            .run(args);
    }

    @Bean
    public SmbSessionFactory smbSessionFactory() {
        SmbSessionFactory smbSession = new SmbSessionFactory();
        smbSession.setHost("myHost");
        smbSession.setPort(445);
        smbSession.setDomain("myDomain");
        smbSession.setUsername("myUser");
        smbSession.setPassword("myPassword");
        smbSession.setShareAndDir("myShareAndDir");
        smbSession.setSmbMinVersion(DialectVersion.SMB210);
        smbSession.setSmbMaxVersion(DialectVersion.SMB311);
        return smbSession;
    }

    @Bean
    public IntegrationFlow smbInboundFlow() {
        return IntegrationFlow
            .from(Smb.inboundAdapter(smbSessionFactory())
                    .preserveTimestamp(true)
                    .remoteDirectory("smbSource")
                    .regexFilter(".*\\.txt$")
                    .localFilename(f -> f.toUpperCase() + ".a")
                    .localDirectory(new File("d:\\smb_files")),
                        e -> e.id("smbInboundAdapter")
                    .autoStartup(true)
                    .poller(Pollers.fixedDelay(5000)))
            .handle(m -> System.out.println(m.getPayload()))
            .get();
    }
}

SMB ストリーミング受信チャネルアダプター

このアダプターは、型 InputStream のペイロードを含むメッセージを生成し、ローカルファイルシステムに書き込むことなくファイルを取得できるようにします。セッションは開いたままであるため、ファイルが消費されると、消費側のアプリケーションがセッションを閉じる必要があります。セッションは closeableResource ヘッダー (IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE) で提供されます。FileSplitter や StreamTransformer などの標準フレームワークコンポーネントは、セッションを自動的に閉じます。これらのコンポーネントの詳細については、ファイル分割およびストリームトランスを参照してください。次の例は、inbound-streaming-channel-adapter を構成する方法を示しています。

<int-smb:inbound-streaming-channel-adapter id="smbInbound"
            channel="smbChannel"
            session-factory="sessionFactory"
            filename-pattern="*.txt"
            filename-regex=".*\.txt"
            filter="filter"
            filter-expression="@myFilterBean.check(#root)"
            remote-file-separator="/"
            comparator="comparator"
            max-fetch-size="1"
            remote-directory-expression="'foo/bar'">
        <int:poller fixed-rate="1000" />
</int-smb:inbound-streaming-channel-adapter>

filename-patternfilename-regexfilter または filter-expression のいずれか 1 つのみが許可されます。

SmbStreamingMessageSource アダプターは、メモリ内 SimpleMetadataStore に基づく SmbPersistentAcceptOnceFileListFilter を使用して リモートファイルの重複を防ぎます。デフォルトでは、このフィルターはファイル名パターン (または正規表現) にも適用されます。重複を許可する必要がある場合は、AcceptAllFileListFilter を使用できます。その他のユースケースは CompositeFileListFilter (または ChainFileListFilter) で処理できます。Java 構成 ( ドキュメントの後半) は、重複を避けるために処理後に リモートファイルを削除する 1 つの手法を示しています。

SmbPersistentAcceptOnceFileListFilter の詳細と使用方法については、リモート永続ファイルリストフィルターを参照してください。

max-fetch-size 属性を使用して、フェッチが必要なときに各ポーリングでフェッチされるファイルの数を制限します。1 に設定し、クラスター環境で実行する場合は永続フィルターを使用します。詳細については、受信チャネルアダプター: リモートファイルフェッチの制御を参照してください。

アダプターは、リモートディレクトリとファイル名をそれぞれ FileHeaders.REMOTE_DIRECTORY ヘッダーと FileHeaders.REMOTE_FILE ヘッダーに入れます。FileHeaders.REMOTE_FILE_INFO ヘッダーは、追加の リモートファイル情報を提供します (デフォルトでは JSON で表されます)。SmbStreamingMessageSource の fileInfoJson プロパティを false に設定すると、ヘッダーに SmbFileInfo オブジェクトが含まれます。

Java 構成を使用した構成

次の Spring Boot アプリケーションは、Java 構成で受信アダプターを構成する方法の例を示しています。

@SpringBootApplication
public class SmbJavaApplication {

    public static void main(String[] args) {
        new SpringApplicationBuilder(SmbJavaApplication.class)
            .web(false)
            .run(args);
    }

    @Bean
    @InboundChannelAdapter(channel = "stream")
    public MessageSource<InputStream> smbMessageSource() {
        SmbStreamingMessageSource messageSource = new SmbStreamingMessageSource(template());
        messageSource.setRemoteDirectory("smbSource/");
        messageSource.setFilter(new AcceptAllFileListFilter<>());
        messageSource.setMaxFetchSize(1);
        return messageSource;
    }

    @Bean
    @Transformer(inputChannel = "stream", outputChannel = "data")
    public org.springframework.integration.transformer.Transformer transformer() {
        return new StreamTransformer("UTF-8");
    }

    @Bean
    public SmbRemoteFileTemplate template() {
        return new SmbRemoteFileTemplate(smbSessionFactory());
    }

    @ServiceActivator(inputChannel = "data", adviceChain = "after")
    @Bean
    public MessageHandler handle() {
        return System.out::println;
    }

    @Bean
    public ExpressionEvaluatingRequestHandlerAdvice after() {
        ExpressionEvaluatingRequestHandlerAdvice advice = new ExpressionEvaluatingRequestHandlerAdvice();
        advice.setOnSuccessExpression(
                "@template.remove(headers['file_remoteDirectory'] + headers['file_remoteFile'])");
        advice.setPropagateEvaluationFailures(true);
        return advice;
    }

}

この例では、トランスフォーマーの下流にあるメッセージハンドラーに、処理後に リモートファイルを削除する advice があることに注意してください。

受信チャネルアダプター: リモートファイルフェッチの制御

受信チャネルアダプターを構成するときに考慮する必要がある 2 つのプロパティがあります。max-messages-per-poll は、すべてのポーラーと同様に、各ポーリングで発行されるメッセージの数を制限するために使用できます (構成された値よりも多くの準備ができている場合)。max-fetch-size は、リモートサーバーから一度に取得するファイルの数を制限できます。

次のシナリオでは、開始状態が空のローカルディレクトリであると想定しています。

  • max-messages-per-poll=2 および max-fetch-size=1: アダプターは、1 つのファイルをフェッチし、それを発行し、次のファイルをフェッチし、それを発行してから、次のポーリングまでスリープします。

  • max-messages-per-poll=2 および max-fetch-size=2): アダプターは両方のファイルをフェッチしてから、それぞれを発行します。

  • max-messages-per-poll=2 および max-fetch-size=4: アダプターは最大 4 つのファイル(使用可能な場合)をフェッチし、最初の 2 つ(少なくとも 2 つある場合)を発行します。次の 2 つのファイルは、次のポーリングで発行されます。

  • max-messages-per-poll=2 および max-fetch-size が指定されていない: アダプターは、すべてのリモートファイルをフェッチし、最初の 2 つを発行します(少なくとも 2 つある場合)。後続のファイルは、後続のポーリングで発行されます(一度に 2 つ)。すべてのファイルが消費されると、リモートフェッチが再度試行され、新しいファイルが取得されます。

アプリケーションの複数のインスタンスをデプロイする場合、1 つのインスタンスがすべてのファイルを「取得」し、他のインスタンスを枯渇させないように、小さな max-fetch-size をお勧めします。

max-fetch-size のもう 1 つの用途は、リモートファイルのフェッチを停止したいが、すでにフェッチされているファイルの処理を続行する場合です。MessageSource で maxFetchSize プロパティを設定すると(プログラムで、JMX を使用して、または制御バスを使用して)、アダプターがそれ以上のファイルをフェッチするのを効果的に停止しますが、ポーラーは以前にフェッチされたファイルのメッセージを送信し続けます。プロパティが変更されたときにポーラーがアクティブである場合、変更は次のポーリングで有効になります。

シンクロナイザには Comparator<SmbFile> を提供できます。これは、maxFetchSize でフェッチされるファイルの数を制限する場合に役立ちます。

SMB 送信チャネルアダプター

ファイルを SMB 共有に書き込む場合、および XML <int-smb:outbound-channel-adapter> コンポーネントの場合は SmbMessageHandler を使用します。Java 構成の場合、SmbMessageHandler を SmbSessionFactory (または SmbRemoteFileTemplate) と共に提供する必要があります。

@Bean
@ServiceActivator(inputChannel = "storeToSmbShare")
public MessageHandler smbMessageHandler(SmbSessionFactory smbSessionFactory) {
    SmbMessageHandler handler = new SmbMessageHandler(smbSessionFactory);
    handler.setRemoteDirectoryExpression(
        new LiteralExpression("remote-target-dir"));
    handler.setFileNameGenerator(m ->
        m.getHeaders().get(FileHeaders.FILENAME, String.class) + ".test");
    handler.setAutoCreateDirectory(true);
    return handler;
}

Java DSL を使用した構成

次の Spring Boot アプリケーションは、Java DSL を使用して送信アダプターを構成する方法の例を示しています。

@SpringBootApplication
@IntegrationComponentScan
public class SmbJavaApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context =
            new SpringApplicationBuilder(SmbJavaApplication.class)
                .web(false)
                .run(args);
        MyGateway gateway = context.getBean(MyGateway.class);
        gateway.sendToSmb(new File("/foo/bar.txt"));
    }

    @Bean
    public SmbSessionFactory smbSessionFactory() {
        SmbSessionFactory smbSession = new SmbSessionFactory();
        smbSession.setHost("myHost");
        smbSession.setPort(445);
        smbSession.setDomain("myDomain");
        smbSession.setUsername("myUser");
        smbSession.setPassword("myPassword");
        smbSession.setShareAndDir("myShareAndDir");
        smbSession.setSmbMinVersion(DialectVersion.SMB210);
        smbSession.setSmbMaxVersion(DialectVersion.SMB311);
        return smbSession;
    }

    @Bean
    public IntegrationFlow smbOutboundFlow() {
        return IntegrationFlow.from("toSmbChannel")
                .handle(Smb.outboundAdapter(smbSessionFactory(), FileExistsMode.REPLACE)
                        .useTemporaryFileName(false)
                        .fileNameExpression("headers['" + FileHeaders.FILENAME + "']")
                        .remoteDirectory("smbTarget")
                ).get();
    }

    @MessagingGateway
    public interface MyGateway {

         @Gateway(requestChannel = "toSmbChannel")
         void sendToSmb(File file);
    }

}

SMB 送信ゲートウェイ

SMB 送信 ゲートウェイは、リモート SMB サーバーと対話するための限られたコマンドセットを提供します。サポートされているコマンドは次のとおりです。

  • ls (リストファイル)

  • nlst (リストファイル名)

  • get (ファイルを取得する)

  • mget (ファイルの取得)

  • rm (ファイルを削除)

  • mv (ファイルの移動 / 名前変更)

  • put (ファイルの送信)

  • mput (複数のファイルを送信する)

ls コマンドの使用

ls はリモートファイルをリストし、次のオプションをサポートします。

  • -1: ファイル名のリストを取得します。デフォルトでは、FileInfo オブジェクトのリストを取得します

  • -a: すべてのファイルを含める ( "." で始まるものを含む)

  • -f: リストをソートしないでください

  • -dirs: インクルードディレクトリ (デフォルトで除外)

  • -links: シンボリックリンクを含める (デフォルトで除外)

  • -R: リモートディレクトリを再帰的にリストする

さらに、ファイル名のフィルタリングは inbound-channel-adapter と同じ方法で提供されます。

ls 操作から生じるメッセージペイロードは、ファイル名のリストまたは FileInfo オブジェクトのリストです(-1 スイッチを usr するかどうかによって異なります)。これらのオブジェクトは、変更された時間、権限などの情報を提供します。

ls コマンドが実行されたリモートディレクトリは、file_remoteDirectory ヘッダーで提供されます。

再帰オプション(-R)を使用する場合、fileName にはサブディレクトリ要素が含まれ、ファイルへの相対パス(リモートディレクトリに対する相対パス)を表します。-dirs オプションを使用する場合、各再帰ディレクトリもリスト内の要素として返されます。この場合、-1 オプションを使用しないことをお勧めします。FileInfo オブジェクトを使用するとファイルとディレクトリを区別できなくなるためです。

nlst コマンドの使用

nlst はリモートファイル名をリストし、1 つのオプションのみをサポートします。

  • -f: リストをソートしないでください

nlst 操作から生じるメッセージペイロードは、ファイル名のリストです。

file_remoteDirectory ヘッダーには、nlst コマンドが実行されたリモートディレクトリが保持されます。

get コマンドの使用

get はリモートファイルを取得し、次のオプションをサポートします。

  • -P: リモートファイルのタイムスタンプを保持します。

  • -stream: リモートファイルをストリームとして取得します。

  • -D: 転送に成功したら、リモートファイルを削除します。FileExistsMode は IGNORE であり、ローカルファイルがすでに存在するため、転送が無視される場合、リモートファイルは削除されません。

file_remoteDirectory ヘッダーはリモートディレクトリを保持し、file_remoteFile ヘッダーはファイル名を保持します。

get 操作の結果として得られるメッセージペイロードは、取得されたファイルを表す File オブジェクトです。-stream オプションを使用する場合、ペイロードは File ではなく InputStream になります。テキストファイルの場合、一般的な使用例は、この操作をファイルスプリッターまたはストリームトランスフォーマーと組み合わせることです。リモートファイルをストリームとして使用する場合、ストリームの使用後に Session を閉じる必要があります。便宜上、Session は closeableResource ヘッダーで提供され、IntegrationMessageHeaderAccessor は便利なメソッドを提供します。

Closeable closeable = new IntegrationMessageHeaderAccessor(message).getCloseableResource();
if (closeable != null) {
    closeable.close();
}

ファイル分割ストリームトランスなどのフレームワークコンポーネントは、データの転送後にセッションを自動的に閉じます。

次の例は、ファイルをストリームとして使用する方法を示しています。

<int-smb:outbound-gateway session-factory="smbSessionFactory"
                            request-channel="inboundGetStream"
                            command="get"
                            command-options="-stream"
                            expression="payload"
                            remote-directory="smbTarget"
                            reply-channel="stream" />

<int-file:splitter input-channel="stream" output-channel="lines" />
カスタムコンポーネントで入力ストリームを使用する場合は、Session を閉じる必要があります。次の例に示すように、カスタムコードでそれを行うか、メッセージのコピーを service-activator にルーティングして SpEL を使用できます。
<int:service-activator input-channel="closeSession"
    expression="headers['closeableResource'].close()" />

mget コマンドの使用

mget は、パターンに基づいて複数のリモートファイルを取得し、次のオプションをサポートします。

  • -P: リモートファイルのタイムスタンプを保持します。

  • -R: ディレクトリツリー全体を再帰的に取得します。

  • -x: パターンに一致するファイルがない場合は例外をスローします(そうでない場合は空のリストが返されます)。

  • -D: 転送が成功したら、各リモートファイルを削除します。転送が無視された場合、FileExistsMode は IGNORE であり、ローカルファイルがすでに存在するため、リモートファイルは削除されません。

mget 操作の結果のメッセージペイロードは、List<File> オブジェクト(つまり、File オブジェクトの List、それぞれが取得したファイルを表す)です。

FileExistsMode が IGNORE の場合、出力メッセージのペイロードには、ファイルがすでに存在するためにフェッチされなかったファイルが含まれなくなりました。以前は、配列には既存のファイルを含むすべてのファイルが含まれていました。

使用する式は、リモートパスが  で終わる結果を生成する必要があることを決定します。たとえば、myfiles/ は myfiles の完全なツリーをフェッチします。

再帰的な MGET を FileExistsMode.REPLACE_IF_MODIFIED モードと組み合わせて使用すると、リモートディレクトリツリー全体をローカルで定期的に同期できます。このモードは、-P (タイムスタンプを保持) オプションに関係なく、ローカルファイルの最終変更タイムスタンプを リモートファイルのタイムスタンプに設定します。

再帰を使用する場合の注意 (-R)

パターンは無視され、* が想定されます。デフォルトでは、リモートツリー全体が取得されます。ただし、FileListFilter を提供することにより、ツリー内のファイルをフィルタリングできます。この方法でツリー内のディレクトリをフィルタリングすることもできます。FileListFilter は、参照によって、または filename-pattern または filename-regex 属性によって提供されます。例: filename-regex="(subDir|.*1.txt)" は、リモートディレクトリおよびサブディレクトリ subDir 内の 1.txt で終わるすべてのファイルを取得します。ただし、この注の後に利用可能な代替手段について説明します。

サブディレクトリをフィルタリングすると、そのサブディレクトリの追加の走査は実行されません。

-dirs オプションは許可されていません(再帰的な mget は再帰的な ls を使用してディレクトリツリーを取得し、ディレクトリ自体をリストに含めることはできません)。

通常、リモートディレクトリ構造がローカルに保持されるように、local-directory-expression で #remoteDirectory 変数を使用します。

永続ファイルリストフィルターにブールプロパティ forRecursion が追加されました。このプロパティを true に設定すると、alwaysAcceptDirectories も設定されます。これは、送信ゲートウェイ(ls および mget)での再帰操作が常にディレクトリツリー全体を毎回トラバースすることを意味します。これは、ディレクトリツリーの奥深くで変更が検出されなかった問題を解決するためです。さらに、forRecursion=true により、ファイルへのフルパスがメタデータストアキーとして使用されます。これにより、同じ名前のファイルが異なるディレクトリに複数回表示された場合にフィルターが正しく機能しなかった問題が解決されます。重要: これは、永続メタデータストア内の既存のキーが、最上位ディレクトリにあるファイルで見つからないことを意味します。このため、プロパティはデフォルトで false です。これは将来のリリースで変更される可能性があります。

alwaysAcceptDirectorties を true に設定することで、常にディレクトリを渡すように SmbSimplePatternFileListFilter および SmbRegexPatternFileListFilter を構成できます。これにより、次の例に示すように、単純なパターンの再帰が可能になります。

<bean id="starDotTxtFilter"
            class="org.springframework.integration.smb.filters.SmbSimplePatternFileListFilter">
    <constructor-arg value="*.txt" />
    <property name="alwaysAcceptDirectories" value="true" />
</bean>

<bean id="dotStarDotTxtFilter"
            class="org.springframework.integration.smb.filters.SmbRegexPatternFileListFilter">
    <constructor-arg value="^.*\.txt$" />
    <property name="alwaysAcceptDirectories" value="true" />
</bean>

ゲートウェイで filter プロパティを使用して、これらのフィルターのいずれかを提供できます。

put コマンドの使用

put はファイルをリモートサーバーに送信します。メッセージのペイロードは、java.io.Filebyte[]String にすることができます。remote-filename-generator (または式)は、リモートファイルに名前を付けるために使用されます。その他の使用可能な属性には、remote-directorytemporary-remote-directory、それらに相当する *-expression (use-temporary-file-name および auto-create-directory)が含まれます。詳細については、スキーマのドキュメント [GitHub] (英語) を参照してください。

put 操作から生じるメッセージペイロードは、転送後のサーバー上のファイルの完全パスを含む String です。

mput コマンドの使用

mput は複数のファイルをサーバーに送信し、次のオプションをサポートします。

  • -R: 再帰 — ディレクトリとサブディレクトリ内のすべてのファイルを送信します(フィルタリングされている場合もあります)

メッセージペイロードは、ローカルディレクトリを表す java.io.File (または String) である必要があります。File または String のコレクションもサポートされています。

put コマンドと同じ属性がサポートされています。さらに、mput-patternmput-regexmput-filter または mput-filter-expression のいずれかを使用して、ローカルディレクトリ内のファイルをフィルタリングできます。サブディレクトリ自体がフィルターを通過する限り、フィルターは再帰で機能します。フィルターを通過しないサブディレクトリは再帰されません。

mput 操作から生じるメッセージペイロードは、List<String> オブジェクト(つまり、転送から生じるリモートファイルパスの List)です。

rm コマンドの使用

rm コマンドにはオプションがありません。

削除操作が成功した場合、結果のメッセージペイロードは Boolean.TRUE です。それ以外の場合、メッセージペイロードは Boolean.FALSE です。file_remoteDirectory ヘッダーはリモートディレクトリを保持し、file_remoteFile ヘッダーはファイル名を保持します。

mv コマンドの使用

mv コマンドにはオプションがありません。

expression 属性は "from" パスを定義し、rename-expression 属性は "to" パスを定義します。デフォルトでは、rename-expression は headers['file_renameTo'] です。この式は、null または空の String と評価されてはなりません。必要に応じて、必要なリモートディレクトリが作成されます。結果メッセージのペイロードは Boolean.TRUE です。file_remoteDirectory ヘッダーは元のリモートディレクトリを保持し、file_remoteFile ヘッダーはファイル名を保持します。file_renameTo ヘッダーは新しいパスを保持します。

remoteDirectoryExpression は、利便性のために mv コマンドで使用できます。"from" ファイルが完全なファイルパスでない場合、remoteDirectoryExpression の結果が リモートディレクトリとして使用されます。たとえば、あるディレクトリ内の リモートファイルの名前を変更するだけのタスクの場合、"to" ファイルにも同じことが当てはまります。

追加のコマンド情報

get および mget コマンドは、local-filename-generator-expression 属性をサポートしています。転送中にローカルファイルの名前を生成する SpEL 式を定義します。評価コンテキストのルートオブジェクトはリクエストメッセージです。remoteFileName 変数も使用できます。mget で特に役立ちます(例: local-filename-generator-expression="#remoteFileName.toUpperCase() + headers.foo")。

get および mget コマンドは、local-directory-expression 属性をサポートしています。転送中にローカルディレクトリの名前を生成する SpEL 式を定義します。評価コンテキストのルートオブジェクトはリクエストメッセージです。remoteDirectory 変数も使用できます。mget で特に役立ちます(例: local-directory-expression="'/tmp/local/' + #remoteDirectory.toUpperCase() + headers.myheader")。この属性は、local-directory 属性と相互に排他的です。

すべてのコマンドについて、ゲートウェイの「式」プロパティは、コマンドが動作するパスを保持します。mget コマンドの場合、式は  に評価される場合があります。これは、すべてのファイル somedirectory/、および * で終わるその他の値を取得することを意味します。

次の例は、ls コマンド用に構成されたゲートウェイを示しています。

<int-smb:outbound-gateway id="gateway1"
        session-factory="smbSessionFactory"
        request-channel="inbound1"
        command="ls"
        command-options="-1"
        expression="payload"
        reply-channel="toSplitter"/>

toSplitter チャネルに送信されるメッセージのペイロードは、String オブジェクトのリストであり、各オブジェクトにはファイルの名前が含まれています。command-options="-1" を省略した場合、ペイロードは FileInfo オブジェクトのリストになります。オプションをスペース区切りリストとして提供できます(例: command-options="-1 -dirs -links")。

GETMGETPUTMPUT コマンドは、FileExistsMode プロパティ (ネームスペースサポートを使用する場合は mode ) をサポートします。これは、ローカルファイルが存在する場合 (GET および MGET) または リモートファイルが存在する場合 (PUT および MPUT) の動作に影響します。サポートされているモードは REPLACEAPPENDFAILIGNORE です。下位互換性のために、PUT および MPUT 操作のデフォルトモードは REPLACE です。GET および MGET 操作の場合、デフォルトは FAIL です。

Java 構成を使用した構成

次の Spring Boot アプリケーションは、Java 構成で送信ゲートウェイを構成する方法の例を示しています。

@SpringBootApplication
public class SmbJavaApplication {

    public static void main(String[] args) {
        new SpringApplicationBuilder(SmbJavaApplication.class)
            .web(false)
            .run(args);
    }

    @Bean
    public SmbSessionFactory smbSessionFactory() {
        SmbSessionFactory smbSession = new SmbSessionFactory();
        smbSession.setHost("myHost");
        smbSession.setPort(445);
        smbSession.setDomain("myDomain");
        smbSession.setUsername("myUser");
        smbSession.setPassword("myPassword");
        smbSession.setShareAndDir("myShareAndDir");
        smbSession.setSmbMinVersion(DialectVersion.SMB210);
        smbSession.setSmbMaxVersion(DialectVersion.SMB311);
        return smbSession;
    }

    @Bean
    @ServiceActivator(inputChannel = "smbChannel")
    public MessageHandler handler() {
        SmbOutboundGateway smbOutboundGateway =
            new SmbOutboundGateway(smbSessionFactory(), "'my_remote_dir/'");
        smbOutboundGateway.setOutputChannelName("replyChannel");
        return smbOutboundGateway;
    }

}

Java DSL を使用した構成

次の Spring Boot アプリケーションは、送信ゲートウェイを Java DSL で構成する方法の例を示しています。

@SpringBootApplication
public class SmbJavaApplication {

    public static void main(String[] args) {
        new SpringApplicationBuilder(SmbJavaApplication.class)
            .web(false)
            .run(args);
    }

    @Bean
    public SmbSessionFactory smbSessionFactory() {
        SmbSessionFactory smbSession = new SmbSessionFactory();
        smbSession.setHost("myHost");
        smbSession.setPort(445);
        smbSession.setDomain("myDomain");
        smbSession.setUsername("myUser");
        smbSession.setPassword("myPassword");
        smbSession.setShareAndDir("myShareAndDir");
        smbSession.setSmbMinVersion(DialectVersion.SMB210);
        smbSession.setSmbMaxVersion(DialectVersion.SMB311);
        return smbSession;
    }

    @Bean
    public SmbOutboundGatewaySpec smbOutboundGateway() {
        return Smb.outboundGateway(smbSessionFactory(),
            AbstractRemoteFileOutboundGateway.Command.MGET, "payload")
            .options(AbstractRemoteFileOutboundGateway.Option.RECURSIVE)
            .regexFileNameFilter("(subSmbSource|.*.txt)")
            .localDirectoryExpression("'localDirectory/' + #remoteDirectory")
            .localFilenameExpression("#remoteFileName.replaceFirst('smbSource', 'localTarget')");
    }

    @Bean
    public IntegrationFlow smbFlow(AbstractRemoteFileOutboundGateway<SmbFile> smbOutboundGateway) {
        return f -> f
            .handle(smbOutboundGateway)
            .channel(c -> c.queue("remoteFileOutputChannel"));
    }

}

送信ゲートウェイの部分的な成功 (mget および mput)

mget および mput を使用して) 複数のファイルに対して操作を実行すると、1 つ以上のファイルが転送された後、しばらくして例外が発生する可能性があります。この場合、PartialSuccessException がスローされます。通常の MessagingException プロパティ (failedMessage および cause) と同様に、この例外には 2 つの追加プロパティがあります。

  • partialResults: 正常な転送結果。

  • derivedInput: リクエストメッセージから生成されたファイルのリスト(mput 用に転送するローカルファイルなど)。

これらの属性により、正常に転送されたファイルと転送されなかったファイルを判別できます。

再帰的な mput の場合、PartialSuccessException にはネストされた PartialSuccessException インスタンスがあります。

次のディレクトリ構造を考慮してください。

root/
|- file1.txt
|- subdir/
   | - file2.txt
   | - file3.txt
|- zoo.txt

file3.txt で例外が発生した場合、ゲートウェイによってスローされた PartialSuccessException には、file1.txtsubdirzoo.txt の derivedInput と file1.txt の partialResults があります。その cause は、file2.txt の derivedInput と file2.txt の file3.txt および partialResults を備えた別の PartialSuccessException です。

リモートファイル情報

SmbStreamingMessageSource ( SMB ストリーミング受信チャネルアダプター )、SmbInboundFileSynchronizingMessageSource ( SMB 受信チャネルアダプター )、および SmbOutboundGateway ( SMB 送信ゲートウェイ ) の「読み取り」-commands は、メッセージに追加のヘッダーを提供し、リモートファイルに関する情報を生成します。

  • FileHeaders.REMOTE_HOST_PORT - ファイル転送操作中にリモートセッションが接続された host:port ペア。

  • FileHeaders.REMOTE_DIRECTORY - 操作が実行されたリモートディレクトリ。

  • FileHeaders.REMOTE_FILE - リモートファイル名。単一ファイル操作にのみ適用されます。

SmbInboundFileSynchronizingMessageSource は リモートファイルに対してメッセージを生成しませんが、ローカルコピーを使用するため、AbstractInboundFileSynchronizer は リモートファイルに関する情報を、同期操作中に URI スタイル (protocol://host:port/remoteDirectory#remoteFileName) で MetadataStore (外部で構成可能) に保存します。このメタデータは、ローカルファイルがポーリングされるときに SmbInboundFileSynchronizingMessageSource によって取得されます。ローカルファイルが削除されたら、そのメタデータエントリを削除することをお勧めします。AbstractInboundFileSynchronizer は、この目的のために removeRemoteFileMetadata() コールバックを提供します。さらに、メタデータキーで使用される setMetadataStorePrefix() があります。同じ MetadataStore インスタンスがこれらのコンポーネント間で共有されている場合、フィルターと AbstractInboundFileSynchronizer の両方がメタデータエントリに同じローカルファイル名を使用するため、エントリのオーバーライドを回避するために、このプレフィックスを MetadataStore ベースの FileListFilter 実装で使用されるものとは異なるものにすることをお勧めします。鍵。