= Split unzipped content into Rabbit Binder destination

This sample demonstrates how out of the box catalog functions and custom functions can be composed, and how the final result can be bound to RabbitMQ destination by the https://spring.io/projects/spring-cloud-function[Spring Cloud Stream] framework.
The goal of this sample is to poll zip files, unzip them, and emit messages to RabbitMQ for every line of text from those zip entries.

The sample uses these dependencies:

[source,groovy]
----
implementation 'org.springframework.cloud:spring-cloud-stream-binder-rabbit'
implementation 'org.springframework.integration:spring-integration-zip'
implementation 'org.springframework.cloud.fn:spring-file-supplier'
implementation 'org.springframework.cloud.fn:spring-splitter-function'
----

The first one is for binding output of the composed function into a RabbitMQ destination.
The second one is for `UnZipTransformer`, which we use for a custom function to unzip polled files by the `fileSupplier`.
The `splitterFunction` is used in a `FileSplitter` mode to read lines from unzipped entries and emit each of them as an individual message.
Essentially, we are splitting twice: zip entries, and content of each file.

The composition is like this: `fileSupplier|unzipFunction|splitterFunction|flattenFunction`.
(The `flattenFunction` will be explained latter).
The result of this composition is a `Supplier<Flux<Mesage<?>>>` and we bind it into a RabbitMQ `unzipped_data_exchange` using Spring Cloud Stream.

For `fileSupplier` we provide these configuration properties:

[source,yaml]
----
file:
  supplier:
    directory: # Set some real dir with zips to process
    filename-pattern: '*.zip'
----

Poll only zip files from the provided directory.
The sample doesn't come with one, so it's up to an end-user to provide specific directory with zip files.
Or this `fileSupplier` could be replaced with any other file-based supplier.

The `splitterFunction` comes with this property:

[source,yaml]
----
splitter:
  charset: UTF-8
----

Which is a trigger for that function to use a `FileSplitter` for zip entries to emit their lines of text as individual messages.

The custom `ZipSplitRabbitBinderApplication.unzipFunction()` (might be a candidate for the future Functions Catalog version) uses `Flux` API to unzip polled files via `UnZipTransformer` and then `flatMapIterable()` for zip entries.
Then those entries are fed into a `splitterFunction` for `FileSplitter` mode.

The mention `ZipSplitRabbitBinderApplication.flattenFunction()` is needed for now here since `splitterFucntion` produces a `List<Message>` which cannot be https://docs.spring.io/spring-cloud-stream/reference/spring-cloud-stream/producing-and-consuming-messages.html#batch-producers[de-batched] by Spring Cloud Stream since our final product of the composition is, essentially, `Supplier<Flux<Message<?>>>`.

To run the application from main `ZipSplitRabbitBinderApplication` class (`./gradlew bootRun`), the RabbitMQ broker must be supplied on the target environment.

The test environment for this sample uses `org.springframework.boot:spring-boot-testcontainers` and `org.testcontainers:rabbitmq` to run RabbitMQ in Docker container and wire it properly into Spring Boot auto-configuration.
The `ZipSplitRabbitBinderApplicationTests` uses `dirWithZips` directory from classpath with two zip files.
Then the `fileSupplier` polls those files and emits them into the mentioned function composition.
The `@RabbitListener` in the test configuration bind an anonymous queue to the mentioned `unzipped_data_exchange` topic exchange to consume produced data from our functions composition.
The test, by itself, verifies that all consumed by `@RabbitListener` data is, essentially, lines from the mentioned zipped files.