I have a solution using a Apache File component that picks up a file, process it and moves the file to error
when an exception occurs or moves the file to processed
otherwise. All fine, all working as excpected.
Now for one type of exception (let's call it MySpecialException
) I want the file not to be moved to error
but stay where it was found, the file lock released and picked up again on the next poll.
The reason is due to an external situation the file cannot be processed but there is nothing wrong with the file itself. So it must be processed before any other files over and over again until the external situation gets solved.
My file component Uri for standard behavior:
from("file://" + fileDirectory
+ "?recursive=false"
+ "&delay=" + fileDelay
// Sort on oldest first, then name
+ "&sortBy=file:modified;file:name"
+ "&readLock=changed"
+ "&readLockCheckInterval=5000"
+ "&readLockLoggingLevel=DEBUG"
+ "&move=${file:parent}/processed/${file:onlyname.noext}-trace=${exchangeProperty.myTraceId"}.${file:name.ext}"
+ "&moveFailed=error"
+ "&maxMessagesPerPoll=1")
I tried the route to use a custom processStrategy
by adding &processStrategy=#customFileProcessStrategy
to the uri and implement it like (after many variations):
@Component
@Slf4j
public class CustomFileProcessStrategy<T> extends GenericFileRenameProcessStrategy<T> {
private final FileChangedExclusiveReadLockStrategy readLockStrategy = new FileChangedExclusiveReadLockStrategy();
public CustomFileProcessStrategy() {
super.setExclusiveReadLockStrategy((GenericFileExclusiveReadLockStrategy<T>) readLockStrategy);
}
@Override
public boolean begin(GenericFileOperations<T> operations, GenericFileEndpoint<T> endpoint, Exchange exchange, GenericFile<T> file) throws Exception {
return super.begin(operations, endpoint, exchange, file);
}
@Override
public void abort(GenericFileOperations<T> operations, GenericFileEndpoint<T> endpoint, Exchange exchange, GenericFile<T> file) throws Exception {
super.abort(operations, endpoint, exchange, file);
}
@Override
public void commit(GenericFileOperations<T> operations, GenericFileEndpoint<T> endpoint, Exchange exchange, GenericFile<T> file) throws Exception {
supermit(operations, endpoint, exchange, file);
}
@Override
public void rollback(GenericFileOperations<T> operations, GenericFileEndpoint<T> endpoint, Exchange exchange, GenericFile<T> file) throws Exception {
if (exchange.isFailed()) {
Exception ex = exchange.getException();
if (ex == null) {
ex = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
}
if (!isMySpecialException(ex)) {
super.rollback(operations, endpoint, exchange, file);
} else {
log.trace("Detected isMySpecialException. Not moving input file so it can be picked up again.");
((GenericFileExclusiveReadLockStrategy<T>)readLockStrategy).releaseExclusiveReadLockOnRollback(operations, file, exchange);
}
} else {
super.rollback(operations, endpoint, exchange, file);
}
}
}
As per documentation:
If this option is set then the readLock option does not apply.
I do want readlocks so I set GenericFileExclusiveReadLockStrategy
in the constructor.
Now I have a lock. But now the file will never be moved because the renamers in the GenericFileRenameProcessStrategy
are also not set and therefore not used. So I looked at also setting these. Then I stopped..
Problem with continuing this route is that I need to more and more copy implementation logic from all kinds of component related classes. That seems a bit too custom for me, especially when the component get's updated.
So I would like to know if there is a kind of official way to achieve what I want.
Either by implementing a processStrategy
differently or maybe use another strategy?
I'm using Apache Camel v4.0.6, Spring boot v3.1.12, Java 17.
Thanks.