Use LogAccessor from SF

* Change main classes to use a `LogAccessor` API to simplify code flow
* Fix tests according `LogAccessor` property
* Fix some Sonar smells
This commit is contained in:
Artem Bilan
2020-10-06 13:56:50 -04:00
parent a66e82b0aa
commit c7ff99a4e8
95 changed files with 1165 additions and 1432 deletions

View File

@@ -145,8 +145,7 @@ public class FileReadingMessageSource extends AbstractMessageSource<File>
*/
public FileReadingMessageSource(int internalQueueCapacity) {
this(null);
Assert.isTrue(internalQueueCapacity > 0,
"Cannot create a queue with non positive capacity");
Assert.isTrue(internalQueueCapacity > 0, "Cannot create a queue with non positive capacity");
this.scanner = new HeadDirectoryScanner(internalQueueCapacity);
}
@@ -383,9 +382,7 @@ public class FileReadingMessageSource extends AbstractMessageSource<File>
Set<File> freshFiles = new LinkedHashSet<>(filteredFiles);
if (!freshFiles.isEmpty()) {
this.toBeReceived.addAll(freshFiles);
if (logger.isDebugEnabled()) {
logger.debug("Added to queue: " + freshFiles);
}
logger.debug(() -> "Added to queue: " + freshFiles);
}
}
@@ -394,9 +391,7 @@ public class FileReadingMessageSource extends AbstractMessageSource<File>
* @param failedMessage the {@link Message} that failed
*/
public void onFailure(Message<File> failedMessage) {
if (logger.isWarnEnabled()) {
logger.warn("Failed to send: " + failedMessage);
}
logger.warn(() -> "Failed to send: " + failedMessage);
this.toBeReceived.offer(failedMessage.getPayload());
}
@@ -440,8 +435,8 @@ public class FileReadingMessageSource extends AbstractMessageSource<File>
try {
this.watcher = FileSystems.getDefault().newWatchService();
}
catch (IOException e) {
logger.error("Failed to create watcher for " + FileReadingMessageSource.this.directory, e);
catch (IOException ex) {
logger.error(ex, () -> "Failed to create watcher for " + FileReadingMessageSource.this.directory);
}
this.kinds = new WatchEvent.Kind<?>[FileReadingMessageSource.this.watchEvents.length];
@@ -462,8 +457,8 @@ public class FileReadingMessageSource extends AbstractMessageSource<File>
this.watcher = null;
this.pathKeys.clear();
}
catch (IOException e) {
logger.error("Failed to close watcher for " + FileReadingMessageSource.this.directory, e);
catch (IOException ex) {
logger.error(ex, () -> "Failed to close watcher for " + FileReadingMessageSource.this.directory);
}
}
@@ -474,7 +469,7 @@ public class FileReadingMessageSource extends AbstractMessageSource<File>
@Override
protected File[] listEligibleFiles(File directory) {
Assert.state(this.watcher != null, "The WatchService has'nt been started");
Assert.state(this.watcher != null, "The WatchService hasn't been started");
Set<File> files = new LinkedHashSet<>();
@@ -513,17 +508,15 @@ public class FileReadingMessageSource extends AbstractMessageSource<File>
private void processFilesFromNormalEvent(Set<File> files, File parentDir, WatchEvent<?> event) {
Path item = (Path) event.context();
File file = new File(parentDir, item.toFile().getName());
if (logger.isDebugEnabled()) {
logger.debug("Watch event [" + event.kind() + "] for file [" + file + "]");
}
logger.debug(() -> "Watch event [" + event.kind() + "] for file [" + file + "]");
if (event.kind() == StandardWatchEventKinds.ENTRY_DELETE) {
if (getFilter() instanceof ResettableFileListFilter) {
((ResettableFileListFilter<File>) getFilter()).remove(file);
}
boolean fileRemoved = files.remove(file);
if (fileRemoved && logger.isDebugEnabled()) {
logger.debug("The file [" + file +
if (fileRemoved) {
logger.debug(() -> "The file [" + file +
"] has been removed from the queue because of DELETE event.");
}
}
@@ -538,19 +531,15 @@ public class FileReadingMessageSource extends AbstractMessageSource<File>
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("A file [" + file + "] for the event [" + event.kind() +
"] doesn't exist. Ignored.");
}
logger.debug(() -> "A file [" + file + "] for the event [" + event.kind() +
"] doesn't exist. Ignored.");
}
}
}
private void processFilesFromOverflowEvent(Set<File> files, WatchEvent<?> event) {
if (logger.isDebugEnabled()) {
logger.debug("Watch event [" + StandardWatchEventKinds.OVERFLOW +
"] with context [" + event.context() + "]");
}
logger.debug(() -> "Watch event [" + StandardWatchEventKinds.OVERFLOW +
"] with context [" + event.context() + "]");
for (WatchKey watchKey : this.pathKeys.values()) {
watchKey.cancel();
@@ -589,17 +578,15 @@ public class FileReadingMessageSource extends AbstractMessageSource<File>
});
}
catch (IOException e) {
logger.error("Failed to walk directory: " + directory.toString(), e);
catch (IOException ex) {
logger.error(ex, () -> "Failed to walk directory: " + directory.toString());
}
return walkedFiles;
}
private void registerWatch(Path dir) throws IOException {
if (!this.pathKeys.containsKey(dir)) {
if (logger.isDebugEnabled()) {
logger.debug("registering: " + dir + " for file events");
}
logger.debug(() -> "registering: " + dir + " for file events");
WatchKey watchKey = dir.register(this.watcher, this.kinds);
this.pathKeys.putIfAbsent(dir, watchKey);
}

View File

@@ -515,7 +515,7 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
if (Command.MGET.equals(this.command)) {
Assert.isTrue(!(this.options.contains(Option.SUBDIRS)),
"Cannot use " + Option.SUBDIRS.toString() + " when using 'mget' use " +
() -> "Cannot use " + Option.SUBDIRS.toString() + " when using 'mget' use " +
Option.RECURSIVE.toString() + " to obtain files in subdirectories");
}
@@ -544,9 +544,7 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
if (!localDirectory.exists()) {
try {
if (this.autoCreateLocalDirectory) {
if (logger.isDebugEnabled()) {
logger.debug("The '" + localDirectory + "' directory doesn't exist; Will create.");
}
logger.debug(() -> "The '" + localDirectory + "' directory doesn't exist; Will create.");
if (!localDirectory.mkdirs()) {
throw new IOException("Failed to make local directory: " + localDirectory);
}
@@ -646,7 +644,7 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
String remoteFilePath = obtainRemoteFilePath(requestMessage);
String remoteFilename = getRemoteFilename(remoteFilePath);
String remoteDir = getRemoteDirectory(remoteFilePath, remoteFilename);
Session<F> session = null;
Session<F> session;
Object payload;
if (this.options.contains(Option.STREAM)) {
session = this.remoteFileTemplate.getSessionFactory().getSession();
@@ -767,7 +765,7 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
if (lastSeparator > 0) {
String remoteFileDirectory = remoteFileNewPath.substring(0, lastSeparator + 1);
RemoteFileUtils.makeDirectories(remoteFileDirectory, session,
this.remoteFileTemplate.getRemoteFileSeparator(), this.logger);
this.remoteFileTemplate.getRemoteFileSeparator(), this.logger.getLog());
}
session.rename(remoteFilePath, remoteFileNewPath);
return true;
@@ -840,8 +838,7 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
}
else {
File localDir = file;
return this.remoteFileTemplate.invoke(t ->
mPut(requestMessage, t.getSession(), localDir));
return this.remoteFileTemplate.invoke(t -> mPut(requestMessage, t.getSession(), localDir));
}
}
@@ -869,8 +866,9 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
if (path != null) {
replies.add(path);
}
else if (logger.isDebugEnabled()) {
logger.debug("File " + filteredFile.getAbsolutePath() + " removed before transfer; ignoring");
else {
logger.debug(() ->
"File " + filteredFile.getAbsolutePath() + " removed before transfer; ignoring");
}
}
else if (this.options.contains(Option.RECURSIVE)) {
@@ -1033,7 +1031,7 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
}
fileInfo = files[0];
}
File localFile =
final File localFile =
new File(generateLocalDirectory(message, remoteDir), generateLocalFileName(message, remoteFilename));
FileExistsMode existsMode = this.fileExistsMode;
boolean appending = FileExistsMode.APPEND.equals(existsMode);
@@ -1051,8 +1049,8 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
else {
outputStream = new BufferedOutputStream(new FileOutputStream(tempFile));
}
if (replacing && !localFile.delete() && this.logger.isWarnEnabled()) {
this.logger.warn("Failed to delete " + localFile);
if (replacing && !localFile.delete()) {
this.logger.warn(() -> "Failed to delete " + localFile);
}
try {
session.read(remoteFilePath, outputStream);
@@ -1062,8 +1060,8 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
and the file can't be deleted without closing streams before.
*/
outputStream.close();
if (!tempFile.delete() && this.logger.isWarnEnabled()) {
this.logger.warn("Failed to delete tempFile " + tempFile);
if (!tempFile.delete()) {
this.logger.warn(() -> "Failed to delete tempFile " + tempFile);
}
if (e instanceof RuntimeException) {
@@ -1086,8 +1084,8 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
}
if ((this.options.contains(Option.PRESERVE_TIMESTAMP)
|| FileExistsMode.REPLACE_IF_MODIFIED.equals(existsMode))
&& (!localFile.setLastModified(getModified(fileInfo)) && this.logger.isWarnEnabled())) {
logger.warn("Failed to set lastModified on " + localFile);
&& (!localFile.setLastModified(getModified(fileInfo)))) {
logger.warn(() -> "Failed to set lastModified on " + localFile);
}
if (this.options.contains(Option.DELETE)) {
boolean result = session.remove(remoteFilePath);
@@ -1100,11 +1098,9 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
}
}
else if (FileExistsMode.REPLACE_IF_MODIFIED.equals(existsMode)) {
if (logger.isDebugEnabled()) {
logger.debug("Local file '" + localFile + "' has the same modified timestamp, ignored");
}
logger.debug(() -> "Local file '" + localFile + "' has the same modified timestamp, ignored");
if (this.command.equals(Command.MGET)) {
localFile = null;
return null;
}
}
else if (!FileExistsMode.IGNORE.equals(existsMode)) {
@@ -1112,11 +1108,9 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
"Error handling message in the [" + this + "]. Local file " + localFile + " already exists");
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Existing file skipped: " + localFile);
}
logger.debug(() -> "Existing file skipped: " + localFile);
if (this.command.equals(Command.MGET)) {
localFile = null;
return null;
}
}
return localFile;
@@ -1126,7 +1120,7 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
String remoteFilename) throws IOException {
if (this.options.contains(Option.RECURSIVE)) {
if (logger.isWarnEnabled() && !("*".equals(remoteFilename))) {
if (!("*".equals(remoteFilename))) {
logger.warn("File name pattern must be '*' when using recursion");
}
this.options.remove(Option.NAME_ONLY);
@@ -1260,7 +1254,7 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
File localDir = ExpressionUtils.expressionToFile(this.localDirectoryExpression, evaluationContext, message,
"Local Directory");
if (!localDir.exists()) {
Assert.isTrue(localDir.mkdirs(), "Failed to make local directory: " + localDir);
Assert.isTrue(localDir.mkdirs(), () -> "Failed to make local directory: " + localDir);
}
return localDir;
}

View File

@@ -24,6 +24,7 @@ import java.util.Arrays;
import java.util.Comparator;
import java.util.regex.Pattern;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.integration.endpoint.AbstractFetchLimitingMessageSource;
import org.springframework.integration.file.DefaultDirectoryScanner;
@@ -179,11 +180,9 @@ public abstract class AbstractInboundFileSynchronizingMessageSource<F>
try {
if (!this.localDirectory.exists()) {
if (this.autoCreateLocalDirectory) {
if (logger.isDebugEnabled()) {
logger.debug("The '" + this.localDirectory + "' directory doesn't exist; Will create.");
}
if (!this.localDirectory.mkdirs() && this.logger.isWarnEnabled()) {
this.logger.warn("Failed to create directories for " + this.localDirectory);
logger.debug(() -> "The '" + this.localDirectory + "' directory doesn't exist; Will create.");
if (!this.localDirectory.mkdirs()) {
this.logger.warn(() -> "Failed to create directories for " + this.localDirectory);
}
}
else {
@@ -192,8 +191,9 @@ public abstract class AbstractInboundFileSynchronizingMessageSource<F>
}
this.fileSource.setDirectory(this.localDirectory);
initFiltersAndScanner();
if (this.getBeanFactory() != null) {
this.fileSource.setBeanFactory(getBeanFactory());
BeanFactory beanFactory = getBeanFactory();
if (beanFactory != null) {
this.fileSource.setBeanFactory(beanFactory);
}
this.fileSource.afterPropertiesSet();
this.synchronizer.afterPropertiesSet();
@@ -241,8 +241,8 @@ public abstract class AbstractInboundFileSynchronizingMessageSource<F>
this.fileSource.stop();
this.synchronizer.close();
}
catch (IOException e) {
logger.error("Error closing synchronizer", e);
catch (IOException ex) {
logger.error(ex, "Error closing synchronizer");
}
}

View File

@@ -43,21 +43,21 @@ import org.springframework.util.Assert;
public abstract class FileTailingMessageProducerSupport extends MessageProducerSupport
implements ApplicationEventPublisherAware {
private volatile File file;
private volatile ApplicationEventPublisher eventPublisher;
private volatile TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();
private volatile long tailAttemptsDelay = 5000;
private final AtomicLong lastNoMessageAlert = new AtomicLong();
private File file;
private ApplicationEventPublisher eventPublisher;
private TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();
private long tailAttemptsDelay = 5000;
private long idleEventInterval = 0;
private volatile long lastProduce = System.currentTimeMillis();
private ScheduledFuture<?> idleEventScheduledFuture;
private volatile ScheduledFuture<?> idleEventScheduledFuture;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
@@ -33,36 +33,33 @@ import org.springframework.util.Assert;
* @author Gary Russell
* @author Gavin Gray
* @author Ali Shahbour
* @author Artem Bilan
*
* @since 3.0
*
*/
public class OSDelegatingFileTailingMessageProducer extends FileTailingMessageProducerSupport
implements SchedulingAwareRunnable {
private volatile Process nativeTailProcess;
private boolean enableStatusReader = true;
private volatile String options = "-F -n 0";
private String options = "-F -n 0";
private volatile String command = "ADAPTER_NOT_INITIALIZED";
private volatile boolean enableStatusReader = true;
private volatile Process nativeTailProcess;
private volatile BufferedReader stdOutReader;
public void setOptions(String options) {
if (options == null) {
this.options = "";
}
else {
this.options = options;
}
this.options = options == null ? "" : options;
}
/**
* If false, thread for capturing stderr will not be started
* and stderr output will be ignored
* @param enableStatusReader true or false
* @since 4.3.6
* @since 4.3.6
*/
public void setEnableStatusReader(boolean enableStatusReader) {
this.enableStatusReader = enableStatusReader;
@@ -84,16 +81,16 @@ public class OSDelegatingFileTailingMessageProducer extends FileTailingMessagePr
@Override
protected void onInit() {
Assert.notNull(getFile(), "File cannot be null");
super.onInit();
Assert.notNull(getFile(), "File cannot be null");
}
@Override
protected void doStart() {
super.doStart();
destroyProcess();
this.command = "tail " + this.options + " " + this.getFile().getAbsolutePath();
this.getTaskExecutor().execute(this::runExec);
this.command = "tail " + this.options + " " + getFile().getAbsolutePath();
getTaskExecutor().execute(this::runExec);
}
@Override
@@ -142,34 +139,26 @@ public class OSDelegatingFileTailingMessageProducer extends FileTailingMessagePr
this.getTaskExecutor().execute(() -> {
Process process = OSDelegatingFileTailingMessageProducer.this.nativeTailProcess;
if (process == null) {
if (logger.isDebugEnabled()) {
logger.debug("Process destroyed before starting process monitor");
}
logger.debug("Process destroyed before starting process monitor");
return;
}
int result = Integer.MIN_VALUE;
int result;
try {
if (logger.isDebugEnabled()) {
logger.debug("Monitoring process " + process);
}
logger.debug(() -> "Monitoring process " + process);
result = process.waitFor();
if (logger.isInfoEnabled()) {
logger.info("tail process terminated with value " + result);
}
logger.info(() -> "tail process terminated with value " + result);
}
catch (InterruptedException e) {
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
logger.error("Interrupted - stopping adapter", e);
logger.error(ex, "Interrupted - stopping adapter");
stop();
}
finally {
destroyProcess();
}
if (isRunning()) {
if (logger.isInfoEnabled()) {
logger.info("Restarting tail process in " + getMissingFileDelay() + " milliseconds");
}
logger.info(() -> "Restarting tail process in " + getMissingFileDelay() + " milliseconds");
getTaskScheduler()
.schedule(this::runExec, new Date(System.currentTimeMillis() + getMissingFileDelay()));
}
@@ -183,41 +172,32 @@ public class OSDelegatingFileTailingMessageProducer extends FileTailingMessagePr
private void startStatusReader() {
Process process = this.nativeTailProcess;
if (process == null) {
if (logger.isDebugEnabled()) {
logger.debug("Process destroyed before starting stderr reader");
}
logger.debug("Process destroyed before starting stderr reader");
return;
}
this.getTaskExecutor().execute(() -> {
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String statusMessage;
if (logger.isDebugEnabled()) {
logger.debug("Reading stderr");
}
try {
while ((statusMessage = errorReader.readLine()) != null) {
publish(statusMessage);
if (logger.isTraceEnabled()) {
logger.trace(statusMessage);
getTaskExecutor()
.execute(() -> {
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String statusMessage;
logger.debug("Reading stderr");
try {
while ((statusMessage = errorReader.readLine()) != null) {
publish(statusMessage);
logger.trace(statusMessage);
}
}
}
}
catch (IOException e1) {
if (logger.isDebugEnabled()) {
logger.debug("Exception on tail error reader", e1);
}
}
finally {
try {
errorReader.close();
}
catch (IOException e2) {
if (logger.isDebugEnabled()) {
logger.debug("Exception while closing stderr", e2);
catch (IOException e1) {
logger.debug(e1, "Exception on tail error reader");
}
}
}
});
finally {
try {
errorReader.close();
}
catch (IOException e2) {
logger.debug(e2, "Exception while closing stderr");
}
}
});
}
/**
@@ -227,26 +207,20 @@ public class OSDelegatingFileTailingMessageProducer extends FileTailingMessagePr
public void run() {
String line;
try {
if (logger.isDebugEnabled()) {
logger.debug("Reading stdout");
}
logger.debug("Reading stdout");
while ((line = this.stdOutReader.readLine()) != null) {
this.send(line);
send(line);
}
}
catch (IOException e) {
if (logger.isDebugEnabled()) {
logger.debug("Exception on tail reader", e);
}
catch (IOException ex) {
logger.debug(ex, "Exception on tail reader");
try {
this.stdOutReader.close();
}
catch (IOException e1) {
if (logger.isDebugEnabled()) {
logger.debug("Exception while closing stdout", e);
}
logger.debug(e1, "Exception while closing stdout");
}
this.destroyProcess();
destroyProcess();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
@@ -47,7 +47,6 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.logging.Log;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -56,6 +55,7 @@ import org.junit.jupiter.api.io.TempDir;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.log.LogAccessor;
import org.springframework.expression.Expression;
import org.springframework.integration.channel.NullChannel;
import org.springframework.integration.channel.QueueChannel;
@@ -526,7 +526,7 @@ public class FileWritingMessageHandlerTests {
assertThat(called.get()).isTrue();
handler.stop();
Log logger = spy(TestUtils.getPropertyValue(handler, "logger", Log.class));
LogAccessor logger = spy(TestUtils.getPropertyValue(handler, "logger", LogAccessor.class));
new DirectFieldAccessor(handler).setPropertyValue("logger", logger);
when(logger.isDebugEnabled()).thenReturn(true);
final AtomicInteger flushes = new AtomicInteger();