GH-9452: Expose ZipTransformer.setFileNameGenerator()

Fixes: #9452
Issue link: https://github.com/spring-projects/spring-integration/issues/9452

* Move the logic about `fileNameGenerator` configuration out of `AbstractZipTransformer`
since this property is not used by `UnZipTransformer` implementation
* Add more docs about `ZipTransformer` logic
This commit is contained in:
Artem Bilan
2024-09-12 16:19:17 -04:00
parent e3a46ca528
commit a6c3a30d5b
5 changed files with 56 additions and 52 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2023 the original author or authors.
* Copyright 2015-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,8 +19,6 @@ package org.springframework.integration.zip.transformer;
import java.io.File;
import java.nio.charset.Charset;
import org.springframework.integration.file.DefaultFileNameGenerator;
import org.springframework.integration.file.FileNameGenerator;
import org.springframework.integration.transformer.AbstractTransformer;
import org.springframework.messaging.Message;
import org.springframework.util.Assert;
@@ -37,8 +35,6 @@ public abstract class AbstractZipTransformer extends AbstractTransformer {
protected Charset charset = Charset.defaultCharset();
protected FileNameGenerator fileNameGenerator;
protected ZipResultType zipResultType = ZipResultType.FILE;
protected File workDirectory =
@@ -91,11 +87,6 @@ public abstract class AbstractZipTransformer extends AbstractTransformer {
logger.info(() -> "Creating work directory: " + this.workDirectory);
Assert.isTrue(this.workDirectory.mkdirs(), () -> "Can't create the 'workDirectory': " + this.workDirectory);
}
DefaultFileNameGenerator defaultFileNameGenerator = new DefaultFileNameGenerator();
defaultFileNameGenerator.setBeanFactory(getBeanFactory());
defaultFileNameGenerator.setConversionService(getConversionService());
this.fileNameGenerator = defaultFileNameGenerator;
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2023 the original author or authors.
* Copyright 2015-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,10 +29,13 @@ import org.zeroturnaround.zip.ByteSource;
import org.zeroturnaround.zip.FileSource;
import org.zeroturnaround.zip.ZipEntrySource;
import org.springframework.integration.file.DefaultFileNameGenerator;
import org.springframework.integration.file.FileHeaders;
import org.springframework.integration.file.FileNameGenerator;
import org.springframework.integration.transformer.Transformer;
import org.springframework.integration.zip.ZipHeaders;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
@@ -43,9 +46,6 @@ import org.springframework.util.StringUtils;
* <p>
* See also: <a href="https://www.mindprod.com/jgloss/zip.html"/>
* <p>
* If you want to generate Zip files larger than {@code 4GB}, you must use Java 7:
* <p>
* See also: <a href="https://blogs.oracle.com/xuemingshen/entry/zip64_support_for_4g_zipfile"/>
*
* @author Gunnar Hillert
* @author Artem Bilan
@@ -56,9 +56,11 @@ public class ZipTransformer extends AbstractZipTransformer {
private static final String ZIP_EXTENSION = ".zip";
private volatile int compressionLevel = Deflater.DEFAULT_COMPRESSION;
private int compressionLevel = Deflater.DEFAULT_COMPRESSION;
private volatile boolean useFileAttributes = true;
private boolean useFileAttributes = true;
private FileNameGenerator fileNameGenerator;
/**
* Set the compression level. Default is {@link Deflater#DEFAULT_COMPRESSION}.
@@ -77,6 +79,31 @@ public class ZipTransformer extends AbstractZipTransformer {
this.useFileAttributes = useFileAttributes;
}
/**
* Set a {@link FileNameGenerator} for zip file base name: the {@code .zip} extension is added to this name.
* Unless it already comes with {@code .zip} extension.
* Defaults to the {@link org.springframework.integration.file.DefaultFileNameGenerator}.
* The result of this generator is also used for zip entry(ies) if {@link ZipHeaders#ZIP_ENTRY_FILE_NAME}
* header is not provided in the request message.
* @param fileNameGenerator the {@link FileNameGenerator} to use.
* @since 6.4
*/
public void setFileNameGenerator(FileNameGenerator fileNameGenerator) {
Assert.notNull(fileNameGenerator, "'fileNameGenerator' must not be null");
this.fileNameGenerator = fileNameGenerator;
}
@Override
protected void onInit() {
super.onInit();
if (this.fileNameGenerator == null) {
DefaultFileNameGenerator defaultFileNameGenerator = new DefaultFileNameGenerator();
defaultFileNameGenerator.setBeanFactory(getBeanFactory());
defaultFileNameGenerator.setConversionService(getConversionService());
this.fileNameGenerator = defaultFileNameGenerator;
}
}
/**
* The payload may encompass the following types:
* <ul>
@@ -91,39 +118,19 @@ public class ZipTransformer extends AbstractZipTransformer {
@Override
protected Object doZipTransform(Message<?> message) {
Object payload = message.getPayload();
Object zippedData;
MessageHeaders messageHeaders = message.getHeaders();
String baseFileName = this.fileNameGenerator.generateFileName(message);
String zipFileName = baseFileName.endsWith(ZIP_EXTENSION) ? baseFileName : baseFileName + ZIP_EXTENSION;
String zipEntryName;
String zipFileName;
if (message.getHeaders().containsKey(ZipHeaders.ZIP_ENTRY_FILE_NAME)) {
zipEntryName = (String) message.getHeaders().get(ZipHeaders.ZIP_ENTRY_FILE_NAME);
}
else {
zipEntryName = baseFileName;
}
if (message.getHeaders().containsKey(FileHeaders.FILENAME)) {
zipFileName = (String) message.getHeaders().get(FileHeaders.FILENAME);
}
else {
zipFileName = baseFileName + ZIP_EXTENSION;
}
Date lastModifiedDate;
if (message.getHeaders().containsKey(ZipHeaders.ZIP_ENTRY_LAST_MODIFIED_DATE)) {
lastModifiedDate = message.getHeaders().get(ZipHeaders.ZIP_ENTRY_LAST_MODIFIED_DATE, Date.class);
}
else {
lastModifiedDate = new Date();
}
String zipEntryName = (String) messageHeaders.getOrDefault(ZipHeaders.ZIP_ENTRY_FILE_NAME, baseFileName);
Date lastModifiedDate = (Date) messageHeaders.getOrDefault(ZipHeaders.ZIP_ENTRY_LAST_MODIFIED_DATE, new Date());
List<ZipEntrySource> entries = createZipEntries(payload, zipEntryName, lastModifiedDate);
byte[] zippedBytes = SpringZipUtils.pack(entries, this.compressionLevel);
Object zippedData;
if (ZipResultType.FILE.equals(this.zipResultType)) {
final File zippedFile = new File(this.workDirectory, zipFileName);
try {
@@ -145,7 +152,7 @@ public class ZipTransformer extends AbstractZipTransformer {
return getMessageBuilderFactory()
.withPayload(zippedData)
.copyHeaders(message.getHeaders())
.copyHeaders(messageHeaders)
.setHeader(FileHeaders.FILENAME, zipFileName)
.build();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2023 the original author or authors.
* Copyright 2015-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,8 +25,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.integration.channel.AbstractMessageChannel;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.file.DefaultFileNameGenerator;
import org.springframework.integration.file.FileNameGenerator;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.integration.transformer.MessageTransformingHandler;
import org.springframework.integration.zip.transformer.UnZipTransformer;
@@ -64,21 +62,18 @@ public class UnZipTransformerParserTests {
final UnZipTransformer unZipTransformer = TestUtils.getPropertyValue(handler, "transformer", UnZipTransformer.class);
final Charset charset = TestUtils.getPropertyValue(unZipTransformer, "charset", Charset.class);
final FileNameGenerator fileNameGenerator = TestUtils.getPropertyValue(unZipTransformer, "fileNameGenerator", FileNameGenerator.class);
final ZipResultType zipResultType = TestUtils.getPropertyValue(unZipTransformer, "zipResultType", ZipResultType.class);
final File workDirectory = TestUtils.getPropertyValue(unZipTransformer, "workDirectory", File.class);
final Boolean deleteFiles = TestUtils.getPropertyValue(unZipTransformer, "deleteFiles", Boolean.class);
final Boolean expectSingleResult = TestUtils.getPropertyValue(unZipTransformer, "expectSingleResult", Boolean.class);
assertThat(charset).isNotNull();
assertThat(fileNameGenerator).isNotNull();
assertThat(zipResultType).isNotNull();
assertThat(workDirectory).isNotNull();
assertThat(deleteFiles).isNotNull();
assertThat(expectSingleResult).isNotNull();
assertThat(charset).isEqualTo(Charset.defaultCharset());
assertThat(fileNameGenerator).isInstanceOf(DefaultFileNameGenerator.class);
assertThat(zipResultType).isEqualTo(ZipResultType.FILE);
assertThat(workDirectory)
.isEqualTo(new File(System.getProperty("java.io.tmpdir") + File.separator + "ziptransformer"));
@@ -102,21 +97,18 @@ public class UnZipTransformerParserTests {
final UnZipTransformer unZipTransformer = TestUtils.getPropertyValue(handler, "transformer", UnZipTransformer.class);
final Charset charset = TestUtils.getPropertyValue(unZipTransformer, "charset", Charset.class);
final FileNameGenerator fileNameGenerator = TestUtils.getPropertyValue(unZipTransformer, "fileNameGenerator", FileNameGenerator.class);
final ZipResultType zipResultType = TestUtils.getPropertyValue(unZipTransformer, "zipResultType", ZipResultType.class);
final File workDirectory = TestUtils.getPropertyValue(unZipTransformer, "workDirectory", File.class);
final Boolean deleteFiles = TestUtils.getPropertyValue(unZipTransformer, "deleteFiles", Boolean.class);
final Boolean expectSingleResult = TestUtils.getPropertyValue(unZipTransformer, "expectSingleResult", Boolean.class);
assertThat(charset).isNotNull();
assertThat(fileNameGenerator).isNotNull();
assertThat(zipResultType).isNotNull();
assertThat(workDirectory).isNotNull();
assertThat(deleteFiles).isNotNull();
assertThat(expectSingleResult).isNotNull();
assertThat(charset).isEqualTo(Charset.defaultCharset());
assertThat(fileNameGenerator).isInstanceOf(DefaultFileNameGenerator.class);
assertThat(zipResultType).isEqualTo(ZipResultType.FILE);
assertThat(workDirectory)
.isEqualTo(new File(System.getProperty("java.io.tmpdir") + File.separator + "ziptransformer"));

View File

@@ -78,3 +78,9 @@ See xref:sftp/session-factory.adoc[SFTP Session Factory] for more information.
Multiple instances of `MqttPahoMessageDrivenChannelAdapter` and `Mqttv5PahoMessageDrivenChannelAdapter` can now be added at runtime using corresponding `ClientManager` through `IntegrationFlowContext`
Also a `MqttMessageNotDeliveredEvent` event has been introduced to emit when action callback reacts to the delivery failure.
See xref:mqtt.adoc[MQTT Support] for more information.
[[x6.4-zip-support-changes]]
=== Zip Support Changes
The `ZipTransformer` now exposes a `fileNameGenerator` property to customize a target zip file (and optional zip entry) name generation.
See xref:zip.adoc[Zip Support] for more information.

View File

@@ -69,6 +69,14 @@ The `ZipTransformer` can be customized by setting several properties:
Default is `Deflater#DEFAULT_COMPRESSION`.
* `useFileAttributes` - specifies whether the name of the file shall be used for the zip entry.
* `fileNameGenerator` - uses to generate an original file name based on the request message.
Defaults to `DefaultFileNameGenerator`.
The `.zip` extension is added into this name for the target zip file name.
Unless it is already present as a result of this generator.
In addition, a `ZipHeaders.ZIP_ENTRY_FILE_NAME` and `ZipHeaders.ZIP_ENTRY_LAST_MODIFIED_DATE` can be supplied for the name of zip entry and its `lastmodified` attribute.
If not provided, the entry name is exact result of the `fileNameGenerator` and `lastmodified` falls back to the current date and time.
If the payload of request message is an `Iterable`, then this entry name is modified with an index starting `1`.
For example to zip a simple `test.txt` file into a `test.txt.zip`, only this configuration is enough: