INT-4117: File Outbound Set File Permissions
JIRA: https://jira.spring.io/browse/INT-4117 Add an option to set file permissions on the `FileWritingMessageHandler` when the file system supports it. Polishing - PR Comments; more robust file system detection. Add DSL support and fix NPE with missing timestamp header. Fix javadoc Fix javadoc Some polishing: * Add `chmod >= 0` assertion * Make some assertion with string concatenation as `Supplier`-based to deffer that string concatenation
This commit is contained in:
committed by
Artem Bilan
parent
c8aafde20b
commit
2b99c191f6
@@ -29,10 +29,14 @@ import java.io.OutputStreamWriter;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.util.BitSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -48,6 +52,7 @@ import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.integration.expression.ExpressionUtils;
|
||||
import org.springframework.integration.file.support.FileExistsMode;
|
||||
import org.springframework.integration.file.support.FileUtils;
|
||||
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
|
||||
import org.springframework.integration.handler.MessageTriggerAction;
|
||||
import org.springframework.integration.support.locks.DefaultLockRegistry;
|
||||
@@ -152,6 +157,8 @@ public class FileWritingMessageHandler extends AbstractReplyProducingMessageHand
|
||||
|
||||
private volatile boolean preserveTimestamp;
|
||||
|
||||
private Set<PosixFilePermission> permissions;
|
||||
|
||||
/**
|
||||
* Constructor which sets the {@link #destinationDirectoryExpression} using
|
||||
* a {@link LiteralExpression}.
|
||||
@@ -367,6 +374,75 @@ public class FileWritingMessageHandler extends AbstractReplyProducingMessageHand
|
||||
this.preserveTimestamp = preserveTimestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* String setter for Spring XML convenience.
|
||||
* @param chmod permissions as an octal string e.g "600";
|
||||
* @see #setChmod(int)
|
||||
* @since 5.0
|
||||
*/
|
||||
public void setChmodOctal(String chmod) {
|
||||
Assert.notNull(chmod, "'chmod' cannot be null");
|
||||
setChmod(Integer.parseInt(chmod, 8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the file permissions after uploading, e.g. 0600 for
|
||||
* owner read/write. Only applies to file systems that support posix
|
||||
* file permissions.
|
||||
* @param chmod the permissions.
|
||||
* @throws IllegalArgumentException if the value is higher than 0777.
|
||||
* @since 5.0
|
||||
*/
|
||||
public void setChmod(int chmod) {
|
||||
Assert.isTrue(chmod >= 0 && chmod <= 0777, "'chmod' must be between 0 and 0777 (octal)");
|
||||
if (!FileUtils.IS_POSIX) {
|
||||
this.logger.error("'chmod' setting ignored - the file system does not support Posix attributes");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Bitset.valueOf(byte[]) takes a little-endian array of bytes to create a BitSet.
|
||||
* Since we are interested in 9 bits, we construct an array with the low-order byte
|
||||
* (bits 0-7) followed by the second order byte (bit 8).
|
||||
* BitSet.stream() returns a stream of ints representing those bits that are set.
|
||||
* We use that stream with a switch to create the set of PosixFilePermissions
|
||||
* representing the bits that were set in the chmod value.
|
||||
*/
|
||||
BitSet bits = BitSet.valueOf(new byte[] { (byte) chmod, (byte) (chmod >> 8) });
|
||||
final Set<PosixFilePermission> permissions = new HashSet<>();
|
||||
bits.stream().forEach(b -> {
|
||||
switch (b) {
|
||||
case 0:
|
||||
permissions.add(PosixFilePermission.OTHERS_EXECUTE);
|
||||
break;
|
||||
case 1:
|
||||
permissions.add(PosixFilePermission.OTHERS_WRITE);
|
||||
break;
|
||||
case 2:
|
||||
permissions.add(PosixFilePermission.OTHERS_READ);
|
||||
break;
|
||||
case 3:
|
||||
permissions.add(PosixFilePermission.GROUP_EXECUTE);
|
||||
break;
|
||||
case 4:
|
||||
permissions.add(PosixFilePermission.GROUP_WRITE);
|
||||
break;
|
||||
case 5:
|
||||
permissions.add(PosixFilePermission.GROUP_READ);
|
||||
break;
|
||||
case 6:
|
||||
permissions.add(PosixFilePermission.OWNER_EXECUTE);
|
||||
break;
|
||||
case 7:
|
||||
permissions.add(PosixFilePermission.OWNER_WRITE);
|
||||
break;
|
||||
case 8:
|
||||
permissions.add(PosixFilePermission.OWNER_READ);
|
||||
break;
|
||||
}
|
||||
});
|
||||
this.permissions = permissions;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doInit() {
|
||||
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(getBeanFactory());
|
||||
@@ -414,14 +490,14 @@ public class FileWritingMessageHandler extends AbstractReplyProducingMessageHand
|
||||
private void validateDestinationDirectory(File destinationDirectory, boolean autoCreateDirectory) {
|
||||
if (!destinationDirectory.exists() && autoCreateDirectory) {
|
||||
Assert.isTrue(destinationDirectory.mkdirs(),
|
||||
"Destination directory [" + destinationDirectory + "] could not be created.");
|
||||
() -> "Destination directory [" + destinationDirectory + "] could not be created.");
|
||||
}
|
||||
Assert.isTrue(destinationDirectory.exists(),
|
||||
"Destination directory [" + destinationDirectory + "] does not exist.");
|
||||
() -> "Destination directory [" + destinationDirectory + "] does not exist.");
|
||||
Assert.isTrue(destinationDirectory.isDirectory(),
|
||||
"Destination path [" + destinationDirectory + "] does not point to a directory.");
|
||||
() -> "Destination path [" + destinationDirectory + "] does not point to a directory.");
|
||||
Assert.isTrue(Files.isWritable(destinationDirectory.toPath()),
|
||||
"Destination directory [" + destinationDirectory + "] is not writable.");
|
||||
() -> "Destination directory [" + destinationDirectory + "] is not writable.");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -485,7 +561,7 @@ public class FileWritingMessageHandler extends AbstractReplyProducingMessageHand
|
||||
else {
|
||||
if (this.logger.isWarnEnabled()) {
|
||||
this.logger.warn("Could not set lastModified, header " + FileHeaders.SET_MODIFIED
|
||||
+ " must be a Number, not " + timestamp.getClass());
|
||||
+ " must be a Number, not " + (timestamp == null ? "null" : timestamp.getClass()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -730,7 +806,7 @@ public class FileWritingMessageHandler extends AbstractReplyProducingMessageHand
|
||||
fileToWriteTo = tempFile;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unsupported FileExistsMode " + this.fileExistsMode);
|
||||
throw new IllegalStateException("Unsupported FileExistsMode: " + this.fileExistsMode);
|
||||
}
|
||||
return fileToWriteTo;
|
||||
}
|
||||
@@ -745,6 +821,20 @@ public class FileWritingMessageHandler extends AbstractReplyProducingMessageHand
|
||||
if (this.deleteSourceFiles && originalFile != null) {
|
||||
originalFile.delete();
|
||||
}
|
||||
|
||||
setPermissions(resultFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set permissions on newly written files.
|
||||
* @param resultFile the file.
|
||||
* @throws IOException any exception.
|
||||
* @since 5.0
|
||||
*/
|
||||
protected void setPermissions(File resultFile) throws IOException {
|
||||
if (this.permissions != null) {
|
||||
Files.setPosixFilePermissions(resultFile.toPath(), this.permissions);
|
||||
}
|
||||
}
|
||||
|
||||
private void renameTo(File tempFile, File resultFile) throws IOException {
|
||||
|
||||
@@ -75,6 +75,7 @@ abstract class FileWritingMessageHandlerBeanDefinitionBuilder {
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "flush-interval");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "flush-when-idle");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "flush-predicate");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "chmod");
|
||||
String remoteFileNameGenerator = element.getAttribute("filename-generator");
|
||||
String remoteFileNameGeneratorExpression = element.getAttribute("filename-generator-expression");
|
||||
boolean hasRemoteFileNameGenerator = StringUtils.hasText(remoteFileNameGenerator);
|
||||
|
||||
@@ -73,6 +73,8 @@ public class FileWritingMessageHandlerFactoryBean
|
||||
|
||||
private volatile MessageFlushPredicate flushPredicate;
|
||||
|
||||
private String chmod;
|
||||
|
||||
public void setFileExistsMode(String fileExistsModeAsString) {
|
||||
this.fileExistsMode = FileExistsMode.getForString(fileExistsModeAsString);
|
||||
}
|
||||
@@ -137,6 +139,10 @@ public class FileWritingMessageHandlerFactoryBean
|
||||
this.flushPredicate = flushPredicate;
|
||||
}
|
||||
|
||||
public void setChmod(String chmod) {
|
||||
this.chmod = chmod;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FileWritingMessageHandler createHandler() {
|
||||
|
||||
@@ -195,6 +201,9 @@ public class FileWritingMessageHandlerFactoryBean
|
||||
if (this.flushPredicate != null) {
|
||||
handler.setFlushPredicate(this.flushPredicate);
|
||||
}
|
||||
if (this.chmod != null) {
|
||||
handler.setChmodOctal(this.chmod);
|
||||
}
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.springframework.util.Assert;
|
||||
* The {@link MessageHandlerSpec} for the {@link FileWritingMessageHandler}.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @author Gary Russell
|
||||
*
|
||||
* @since 5.0
|
||||
*/
|
||||
@@ -245,6 +246,20 @@ public class FileWritingMessageHandlerSpec
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the file permissions after uploading, e.g. 0600 for
|
||||
* owner read/write. Only applies to file systems that support posix
|
||||
* file permissions.
|
||||
* @param chmod the permissions.
|
||||
* @throws IllegalArgumentException if the value is higher than 0777.
|
||||
* @return the spec.
|
||||
* @see FileWritingMessageHandler#setChmod(int)
|
||||
*/
|
||||
public FileWritingMessageHandlerSpec chmod(int chmod) {
|
||||
this.target.setChmod(chmod);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Object> getComponentsToRegister() {
|
||||
if (this.defaultFileNameGenerator != null) {
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2017 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.file.support;
|
||||
|
||||
import java.nio.file.FileSystems;
|
||||
|
||||
/**
|
||||
* Utilities for operations on Files.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @since 5.0
|
||||
*
|
||||
*/
|
||||
public final class FileUtils {
|
||||
|
||||
public static final boolean IS_POSIX = FileSystems.getDefault().supportedFileAttributeViews().contains("posix");
|
||||
|
||||
private FileUtils() {
|
||||
super();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -597,6 +597,7 @@ Only files matching this regular expression will be picked up by this adapter.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attributeGroup ref="chmod" />
|
||||
<xsd:attributeGroup ref="integration:smartLifeCycleAttributeGroup"/>
|
||||
</xsd:complexType>
|
||||
|
||||
@@ -1027,4 +1028,15 @@ Only files matching this regular expression will be picked up by this adapter.
|
||||
</xsd:attribute>
|
||||
</xsd:attributeGroup>
|
||||
|
||||
<xsd:attributeGroup name="chmod">
|
||||
<xsd:attribute name="chmod" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Change the mode of the file (or remote file) after writing. Integer value
|
||||
expressed in Octal, e.g. '644'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:attributeGroup>
|
||||
|
||||
</xsd:schema>
|
||||
|
||||
@@ -46,7 +46,10 @@ import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -61,9 +64,11 @@ import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.integration.channel.NullChannel;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.file.support.FileExistsMode;
|
||||
import org.springframework.integration.file.support.FileUtils;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.messaging.Message;
|
||||
@@ -123,10 +128,40 @@ public class FileWritingMessageHandlerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportedType() throws Exception {
|
||||
public void permissions() {
|
||||
if (FileUtils.IS_POSIX) {
|
||||
FileWritingMessageHandler handler = new FileWritingMessageHandler(mock(Expression.class));
|
||||
handler.setChmod(0421);
|
||||
Set<?> permissions = TestUtils.getPropertyValue(handler, "permissions", Set.class);
|
||||
assertThat(permissions.size(), equalTo(3));
|
||||
assertTrue(permissions.contains(PosixFilePermission.OWNER_READ));
|
||||
assertTrue(permissions.contains(PosixFilePermission.GROUP_WRITE));
|
||||
assertTrue(permissions.contains(PosixFilePermission.OTHERS_EXECUTE));
|
||||
handler.setChmod(0600);
|
||||
permissions = TestUtils.getPropertyValue(handler, "permissions", Set.class);
|
||||
assertThat(permissions.size(), equalTo(2));
|
||||
assertTrue(permissions.contains(PosixFilePermission.OWNER_READ));
|
||||
assertTrue(permissions.contains(PosixFilePermission.OWNER_WRITE));
|
||||
handler.setChmod(0777);
|
||||
permissions = TestUtils.getPropertyValue(handler, "permissions", Set.class);
|
||||
assertThat(permissions.size(), equalTo(9));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportedTypeAndPermissions() throws Exception {
|
||||
if (FileUtils.IS_POSIX) {
|
||||
handler.setChmod(0777);
|
||||
}
|
||||
handler.setOutputChannel(new NullChannel());
|
||||
handler.handleMessage(new GenericMessage<String>("test"));
|
||||
assertThat(outputDirectory.listFiles()[0], notNullValue());
|
||||
File[] output = outputDirectory.listFiles();
|
||||
assertThat(output.length, equalTo(1));
|
||||
assertThat(output[0], notNullValue());
|
||||
if (FileUtils.IS_POSIX) {
|
||||
Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(output[0].toPath());
|
||||
assertThat(permissions.size(), equalTo(9));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
channel="testChannel"
|
||||
directory="${java.io.tmpdir}"
|
||||
temporary-file-suffix=".foo"
|
||||
chmod="777"
|
||||
filename-generator-expression="'foo.txt'"/>
|
||||
|
||||
<file:outbound-channel-adapter id="adapterWithCustomNameGenerator"
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.integration.file.config;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
@@ -26,6 +27,7 @@ import static org.junit.Assert.assertTrue;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -41,6 +43,7 @@ import org.springframework.integration.file.DefaultFileNameGenerator;
|
||||
import org.springframework.integration.file.FileWritingMessageHandler;
|
||||
import org.springframework.integration.file.FileWritingMessageHandler.MessageFlushPredicate;
|
||||
import org.springframework.integration.file.support.FileExistsMode;
|
||||
import org.springframework.integration.file.support.FileUtils;
|
||||
import org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.messaging.Message;
|
||||
@@ -140,6 +143,9 @@ public class FileOutboundChannelAdapterParserTests {
|
||||
assertEquals("'foo.txt'", expression.getExpressionString());
|
||||
assertEquals(Boolean.FALSE, handlerAccessor.getPropertyValue("deleteSourceFiles"));
|
||||
assertEquals(Boolean.TRUE, handlerAccessor.getPropertyValue("flushWhenIdle"));
|
||||
if (FileUtils.IS_POSIX) {
|
||||
assertThat(TestUtils.getPropertyValue(handler, "permissions", Set.class).size(), equalTo(9));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.integration.file.dsl;
|
||||
|
||||
import static org.hamcrest.Matchers.endsWith;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -74,6 +75,7 @@ import org.springframework.integration.file.filters.ChainFileListFilter;
|
||||
import org.springframework.integration.file.filters.ExpressionFileListFilter;
|
||||
import org.springframework.integration.file.splitter.FileSplitter;
|
||||
import org.springframework.integration.file.support.FileExistsMode;
|
||||
import org.springframework.integration.file.support.FileUtils;
|
||||
import org.springframework.integration.file.tail.ApacheCommonsFileTailingMessageProducer;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
@@ -240,6 +242,9 @@ public class FileTests {
|
||||
endsWith(TestUtils.applySystemFileSeparator("fileWritingFlow/foo.write")));
|
||||
String fileContent = StreamUtils.copyToString(new FileInputStream(resultFile), Charset.defaultCharset());
|
||||
assertEquals(payload, fileContent);
|
||||
if (FileUtils.IS_POSIX) {
|
||||
assertThat(java.nio.file.Files.getPosixFilePermissions(resultFile.toPath()).size(), equalTo(9));
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired
|
||||
@@ -389,7 +394,9 @@ public class FileTests {
|
||||
return IntegrationFlows.from("fileWritingInput")
|
||||
.enrichHeaders(h -> h.header(FileHeaders.FILENAME, "foo.write")
|
||||
.header("directory", new File(tmpDir.getRoot(), "fileWritingFlow")))
|
||||
.handle(Files.outboundGateway(m -> m.getHeaders().get("directory")))
|
||||
.handle(Files.outboundGateway(m -> m.getHeaders().get("directory"))
|
||||
.preserveTimestamp(true)
|
||||
.chmod(0777))
|
||||
.channel(MessageChannels.queue("fileWritingResultChannel"))
|
||||
.get();
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attributeGroup ref="int-file:remoteOutboundAttributeGroup" />
|
||||
<xsd:attributeGroup ref="chmod" />
|
||||
<xsd:attributeGroup ref="int-file:chmod" />
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
@@ -496,7 +496,7 @@
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attributeGroup ref="chmod" />
|
||||
<xsd:attributeGroup ref="int-file:chmod" />
|
||||
<xsd:attributeGroup ref="int-file:remoteOutboundAttributeGroup" />
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
@@ -641,17 +641,6 @@
|
||||
<xsd:attributeGroup ref="integration:smartLifeCycleAttributeGroup"/>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:attributeGroup name="chmod">
|
||||
<xsd:attribute name="chmod" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Change the mode of the remote file after transferring. Integer value
|
||||
expressed in Octal, e.g. '644'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:attributeGroup>
|
||||
|
||||
<xsd:attributeGroup name="tempSuffixGroup">
|
||||
<xsd:attribute name="temporary-file-suffix" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
|
||||
@@ -706,6 +706,12 @@ copy was required).
|
||||
For other payloads, if the `FileHeaders.SET_MODIFIED` header (`file_setModified`) is present, it will be used to set
|
||||
the destination file's `lastModified` timestamp, as long as the header is a `Number`.
|
||||
|
||||
[[file-permissions]]
|
||||
==== File Permissions
|
||||
|
||||
Starting with _version 5.0_, when writing files to a file system that supports Posix permissions, you can specify those permissions on the outbound channel adapter or gateway.
|
||||
The property is an integer and is usually supplied in the familiar octal format; e.g. `0640` meaning the owner has read/write permissions, the group has read only permission and others have no access.
|
||||
|
||||
[[file-outbound-channel-adapter]]
|
||||
==== File Outbound Channel Adapter
|
||||
|
||||
|
||||
@@ -111,7 +111,11 @@ See <<file-tailing>> for more information.
|
||||
The flush predicates for the `FileWritingMessageHandler` now have an additional parameter.
|
||||
See <<file-flushing>> for more information.
|
||||
|
||||
The file outbound channel adapter (`FileWritingMessageHandler`) now supports the `REPLACE_IF_MODIFIED` `FileExistsMode`.
|
||||
The file outbound channel adapter and gateway (`FileWritingMessageHandler`) now support the `REPLACE_IF_MODIFIED` `FileExistsMode`.
|
||||
See <<file-writing-destination-exists>> for more information.
|
||||
|
||||
They also now support setting file permissions on the newly written file.
|
||||
See <<file-permissions>> for more information.
|
||||
|
||||
==== (S)FTP Changes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user