Reputation: 3020
I'm using Spring Boot and I want to get resources.
Here's my directory structure:
├───java
│ └───...
├───resources
│ └───files
│ ├───file1.txt
│ ├───file2.txt
│ ├───file3.txt
│ └───file4.txt
I'm trying to get the resources in the files
directory. Here's what I've done to access these files:
@Autowired
private ResourceLoader resourceLoader;
...
Stream<Path> walk = Files.walk(Paths.get(resourceLoader.getResource("classpath:files/").getURI()));
This works running locally when the files are in the target
directory, but the files are not found when I run it from a JAR file. How do I fix this? I've checked that these files do exist in the jar located under BOOT-INF/classes/files
.
Here's how maven is building and copying the resources into the JAR (I don't want the .txt files to be filtered):
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>**/*.txt</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<includes>
<include>**/*.txt</include>
</includes>
</resource>
</resources>
Upvotes: 5
Views: 5205
Reputation: 609
The below example code does read/load the Drools files configured as part of rules/ folder located under /src/main/resources project path in case of local Windows based development environment i.e. as part of IDE while from application jar in case of Linux/Unix based production environment.
Incorporated the approach to read/load the files using the java.lang.ClassLoader.getResource(String name) method in case of local Windows development environment while used the org.springframework.core.io.support.ResourcePatternUtils.getResourcePatternResolver(ResourceLoader resourceLoader) returned org.springframework.core.io.support.ResourcePatternResolver.getResources(String locationPattern) method to read/load the files from application jar when deployed in Linux based production environment.
NOTE: The above said example will not work if you use the command line to execute the application jar in Windows environment using the below command:
java -jar questionaries-rules-0.0.1-SNAPSHOT.jar
In this case you need to make a call to loadResourcesOfRulesFromJar() method to make it work in Windows or Linux/Unix environment.
You can add the logic to switch between the local development environment and prod environment as per your requirement either by considering OS type along with some configuration mechanism to meet the development and deployment needs.
Drools Configuration
/**
* @author dinesh.lomte
*/
package com.dl.questioneries.rules.api.config;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.runtime.KieContainer;
import org.kie.internal.io.ResourceFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternUtils;
import com.dl.questioneries.rules.api.exception.SystemException;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Configuration
public class DroolsConfiguration {
private final KieServices kieServices = KieServices.Factory.get();
private ResourceLoader resourceLoader;
/**
*
* @param resourceLoader
*/
@Autowired
public DroolsConfiguration(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
/**
*
* @return
* @throws SystemException
*/
@Bean
public KieContainer kieContainer() throws SystemException {
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
File[] files =
System.getProperty("os.name").contains("Windows")
? loadResourcesOfRulesFromLocalSystem()
: loadResourcesOfRulesFromJar();
if (files == null || files.length == 0) {
String message = "Failed to load the '.drl' files located under resources specific rules folder.";
log.error(message);
throw new SystemException(
"SYS_ERROR_00001", message, new Exception(message));
}
for (File file : files) {
kieFileSystem.write(ResourceFactory.newFileResource(file));
}
log.info("Loaded the configured rule files successfully.");
KieBuilder Kiebuilder = kieServices.newKieBuilder(kieFileSystem);
Kiebuilder.buildAll();
return kieServices.newKieContainer(
kieServices.getRepository().getDefaultReleaseId());
}
/**
*
* @return
*/
private File[] loadResourcesOfRulesFromJar() {
log.info("Loading the configured rule files from Jar.");
Resource[] resources = null;
List<File> files = new ArrayList<>();
try {
resources = ResourcePatternUtils
.getResourcePatternResolver(resourceLoader)
.getResources("classpath*:rules/*.drl");
InputStream inputStream = null;
File file = null;
for (Resource resource : resources) {
try {
inputStream = resource.getInputStream();
file = File.createTempFile(
resource.getFilename().substring(
0, resource.getFilename().length() - 4),
".drl");
FileUtils.copyInputStreamToFile(inputStream, file);
} finally {
inputStream.close();
}
log.info("'{}'", resource.getFilename());
files.add(file);
}
} catch (IOException ioException) {
String message = new StringBuilder(
"Failed to load the '.drl' files located under resources specific rules folder.")
.append(ioException.getMessage()).toString();
log.error(message, ioException);
throw new SystemException(
"SYS_ERROR_00001", message, ioException);
}
return (File[]) files.toArray(new File[files.size()]);
}
/**
*
* @return
*/
private File[] loadResourcesOfRulesFromLocalSystem() {
log.info("Loading the configured rule files from local system.");
try {
File files = new File(
getClass().getClassLoader().getResource("rules/").getPath());
return files.listFiles();
} catch (Exception exception) {
String message = new StringBuilder(
"Failed to load the '.drl' files located under resources specific rules folder.")
.append(exception.getMessage()).toString();
log.error(message, exception);
throw new SystemException(
"SYS_ERROR_00001", message, exception);
}
}
}
Rest Controller
/**
* @author dinesh.lomte
*/
package com.dl.questioneries.rules.api.controller;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.dl.questioneries.rules.api.model.Question;
@RestController
public class QuestioneriesRulesController {
@Autowired
private KieContainer kieContainer;
/**
*
* @param question
* @return
*/
@PostMapping(path = "/getQuestion",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public Question fetchQuestion(@RequestBody Question question) {
KieSession kieSession = kieContainer.newKieSession();
kieSession.insert(question);
kieSession.fireAllRules(1);
return question;
}
}
Upvotes: 0
Reputation: 3861
Someone else had the same issue as you and they found the solution by combining the ResourceLoader with the ResourcePatternResolver as Sambit suggested. See here for the same issue with answer: https://stackoverflow.com/a/49826409/6777695
Upvotes: 0
Reputation: 8001
Can you try with the following code to read the files ?
ResourcePatternResolver resourcePatResolver = new PathMatchingResourcePatternResolver();
Resource[] AllResources = resourcePatResolver.getResources("classpath*:files/*.txt");
for(Resource resource: AllResources) {
InputStream inputStream = resource.getInputStream();
//Process the logic
}
This is not the exact solution for the code you have written, but it will give an outline about the resources to read.
Upvotes: 9