How to create a permanent directory for my files with spring boot - spring

I am working with spring boot and spring content. I want to store all my pictures and videos in one directory but my code continues to create different dir every time I rerun the application
I have such bean and when I run the app again it shows null pointer because the dir already exists but I want it to create it just once and every file is stored there
every time i run this tries to create the dir again
#Bean
File filesystemRoot() {
try {
return Files.createDirectory(Paths.get("/tmp/photo_video_myram")).toFile();
} catch (IOException io) {}
return null;
}
#Bean
FileSystemResourceLoader fileSystemResourceLoader() {
return new FileSystemResourceLoader(filesystemRoot().getAbsolutePath());
}

One solution, would be to check if the directory exists:
#Bean
File filesystemRoot() {
File tmpDir = new File("tmp/photo_video_myram");
if (!tmpDir.isDirectory()) {
try {
return Files.createDirectory(tmpDir.toPath()).toFile();
} catch (IOException e) {
e.printStackTrace();
}
}
return tmpDir;
}

You can use isDirectory() method first to check if the directory already exists. In case it does not exist, then create a new one.

Meanwhile there is another way to achieve this, when you use Spring Boot and accordingly spring-content-fs-boot-starter.
According to the documentation at https://paulcwarren.github.io/spring-content/refs/release/fs-index.html#_spring_boot_configuration it should be sufficient to add
spring.content.fs.filesystemRoot=/tmp/photo_video_myram
to your application.properties file.

Related

FileAlreadyExistsException for a deleted directory

For the purpose of making a backup, I copy a directory with tests scripts to another location. For this I'm using Files.walkFileTree(fromDir, SimpleFileVisitor).
This works as expected and I can copy it multiple times without any problems.
But when I delete the target directory via Windows File explorer I get a java.nio.file.FileAlreadyExistsException on the target directory when I try to make a back up.
I'm pretty sure that the target directory is not there.
When I close the Java program and start it again, it works again. It is as if manually deleting the directory locks the 'non-existing' target directory and Java throws a FileAlreadyExistsException.
Here are the relevant parts of the SimpleFileVisitor
I'm using these options when copying the files
StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES, LinkOption.NOFOLLOW_LINKS
#Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException
{
Path copyDir = toDir.resolve(fromDir.relativize(dir));
try {
Files.createDirectories(copyDir);
}
catch(IOException ioe) {
LOG.error("Failed to create directory " + copyDir.toString());
throw ioe;
}
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException
{
Path toFile = toDir.resolve(fromDir.relativize(file));
try {
Files.copy(file, toFile, opts);
}
catch(IOException ioe) {
LOG.error("Failed to create file " + toFile.toString());
throw ioe;
}
return FileVisitResult.CONTINUE;
}
I was expecting that deleting the target directory via Windows File Explorer would not cause this problem, but apparently it does.
Is there anything I could do to make the copy action possible in case someone deletes the directory via Windows File Explorer.

PropertiesLoaderUtils.loadAllProperties is not able to load the property file from src/main/resources

I am using PropertiesLoaderUtils.loadAllProperties(abc.properties);
and have placed abc.properties in src/main/resources folder but still it's not able to get this property file.
Code that we tried ::
try {
props = PropertiesLoaderUtils.loadAllProperties("abc.properties");
} catch (IOException e) {
logger.error("Unable to load file", e);
}
Can someone help me out with the possible cause of not picking up abc.properties whereas if I change it to application.properties, its able to load.

How to use integrationFlows for new files?

I was following a tutorial on how to listen to a folder with spring integration and SseEmitter. I have this code now:
#Bean
IntegrationFlow inboundFlow ( #Value("${input-dir:file:C:\\Users\\kader\\Desktop\\Scaned\\}") File in){
return IntegrationFlows.from(Files.inboundAdapter(in).autoCreateDirectory(true),
poller -> poller.poller(spec -> spec.fixedRate(1000L)))
.transform(File.class, File::getAbsolutePath)
.handle(String.class, (path, map) -> {
sses.forEach((sse) -> {
try {
String p = path;
sse.send(SseEmitter.event().name("spring").data(p));
}
catch (IOException e) {
throw new RuntimeException(e);
}
});
return null ;
})
.get();
}
and it works but it sends all the files in the specified directory including the files that already exist, is there any way to make it ignore them and send the new files only???
Well, actually since you don't configure any filters on the Files.inboundAdapter(), there is a logic like this:
// no filters are provided
else if (Boolean.FALSE.equals(this.preventDuplicates)) {
filtersNeeded.add(new AcceptAllFileListFilter<File>());
}
else { // preventDuplicates is either TRUE or NULL
filtersNeeded.add(new AcceptOnceFileListFilter<File>());
}
Therefore an AcceptOnceFileListFilter is applied and no any already polled files are not going to be picked up on the subsequent poll tasks.
However you really may talk about something like "after application restart", so yes, in this case all the files are going to be pulled.
I believe you need to study what is the FileListFilter and use an appropriate for your use-case: https://docs.spring.io/spring-integration/docs/current/reference/html/files.html#file-reading

CharacterStreamReadingMessageSource.stdin() and EOF

I am using CharacterStreamReadingMessageSource in a spring integration flow:
IntegrationFlows.from(CharacterStreamReadingMessageSource.stdin())
It works. The problem is that if I pipe a file to the process:
cat file | java -jar app.jar
or
java -jar app.jar < file
once the file has been read, the EOF is not propagated, the stdin is still active, and the process does not end. Is there something that I can do to make it behave so? Manually entering ctrl-Z on the command line works as expected, closing the application (Spring boot app, no web).
Unfortunately, it won't work in that scenario; it's designed for console input.
The CharacterStreamReadingMessageSource wraps System.in in a BufferedReader and uses readLine(). Since readLine() blocks and we don't want to tie up a thread for long periods, we check reader.ready(), which returns false if there is no data or the stream is closed.
It should probably provide an option for blocking for this use case, but when used with a real console, it would block forever.
In the meantime, you could create a copy of the class and change receive() ...
#Override
public Message<String> receive() {
try {
synchronized (this.monitor) {
// if (!this.reader.ready()) { // remove this
// return null;
// }
String line = this.reader.readLine();
if (line == null) { // add this
((ConfigurableApplicationContext) getApplicationContext()).close();
}
return (line != null) ? new GenericMessage<String>(line) : null;
}
}
catch (IOException e) {
throw new MessagingException("IO failure occurred in adapter", e);
}
}
(removing the ready check, and shutting down the context at EOF).
I opened a JIRA Issue.

JGit - Get all commits (PlotCommitList) that affected a file/path

Hy i am trying to get all the commits that include a specific directory or file of my repository.
I tried the folowing code :
public PlotCommitList getPlotCommits(String path){
System.out.println(path);
PlotCommitList<PlotLane> plotCommitList = new PlotCommitList<PlotLane>();
PlotWalk revWalk = new PlotWalk(repository);
try {
ObjectId rootId = repository.resolve("HEAD");
if (rootId != null) {
RevCommit root = revWalk.parseCommit(rootId);
revWalk.markStart(root);
revWalk.setTreeFilter(PathFilter.create(path));
plotCommitList.source(revWalk);
plotCommitList.fillTo(Integer.MAX_VALUE);
return plotCommitList;
}
} catch (AmbiguousObjectException ex) {
Logger.getLogger(GitRepository.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(GitRepository.class.getName()).log(Level.SEVERE, null, ex);
}
return plotCommitList;
}
I don't get just the commits that affected that file. I get some "subLists" of the entire list but not just those commits that affected that file.
Maybe TreeFilter doesn't work how i think? I should use other way to get those commits?
I saw the log command has a path filter but i didn't tried it yet because it returns a RevCommit list and for my PlotCommitList i need a revwalk to use as a source. And also i think i cannot cast RevCommit to PlotCommit.
A guy had the same problem here (1st Answer with fileA and fileB issue) : Link - Click Here
You need to combine the PathFilter with an ANY_DIFF filter:
revWalk.setTreeFilter(
AndTreeFilter.create(PathFilter.create(path), TreeFilter.ANY_DIFF));
With only PathFilter I think what happens is that all commits are selected where the specified tree exists (e.g. all commits starting from the initial commit of that file).
Also see the API docs of setTreeFilter or how the LogCommand does it.

Resources