Loading File in External Tomcat Container vs Bootrun - java

I am trying to load a file in Spring.
The file contains Rules based on OpenRules engine.
The problem is when I am using Spring BootRun it is loaded properly.
But when I am trying to deploy the same file in External Tomcat I am getting error FileNotFound.
I am mentioning the file path in property file in the following way:
rules.open.main.decision.path=file:rules/main/Decision.xls
The rules folder is directly under the Project Folder.
In Java I am loading the file:
public Decision getDecisionEngine(){
String decisionName = "CustomerPreventStrategies";
//String fileName = "file:rules/main/Decision.xls";
String fileName = env.getProperty("rules.open.main.decision.path");
System.out.println("rules.open.main.decision.path:"+fileName);
Decision decision = new Decision(decisionName,fileName);
return decision;
}
When I am creating the WAR for external Tomcat I am keeping it in 2 locations. But it is not helping.
war {
baseName = 'MyOpenRules'
version = '0.1.0'
from("rules") {
into("WEB-INF/classes/rules")
}
from("rules") {
into("rules")
}
}
I am getting:
Caused by: java.io.FileNotFoundException: rules\main\Decision.xls (The system cannot find the path specified)

Try using
rules.open.main.decision.path=file:/rules/main/Decision.xls
This makes the Springs to pick from location WEB-INF/classes/rules/main/Decision.xml
When you use
rules.open.main.decision.path=file:rules/main/Decision.xls
the file is expected to be in the current directory. When us start tomcat server through catalina.bat or startup.bat which is inside Tomcat_HOME/bin then bin directory is the current folder for that process. Hence when u kept the file inside tomcat bin that worked.
When u put / spring uses relative path to look for file.

Related

Java find the relative path of the configuration file in the war file

I am trying to access the config.properties file which was previously placed in the config folder. after some research, I moved it to the WEB-INF folder. but even after I moved it, it still return java.lang.NullPointerException whenenver I run my my program. code used to store some password information as below:
ClassLoader resource = ConnectionManager.class.getClass().getClassLoader();
URL path = ConnectionManager.class.getClass().getResource("/WEB-INF/config.properties");
props.load(new FileInputStream(path.getFile()));
String passwordds = props.getProperty("datasource.password");
these are the codes that I found and I try to use it but still I got the null exception.
I cannot use absolute path due to this project will be deploy to production server as in .war file. please advise what is the best way as I am still beginner.
You should check the war your build tool generated, and find where your config file really are.
For maven project, the default resource dir is /src/main/resources/
So /src/main/resources/config.properties will be put at /WEB-INF/classes/config.properties in a war.
You can use getClass().getResourceStream("/config.properties") (getResource sometimes not work will in j2ee environment) to get it.

How to refer to a file inside spring boot application jar as a -D property value while starting the app from command line?

I have a simple spring boot application that needs java.security.krb5.conf property value set to a custom krb5.conf file. I have added the file inside the src/main/resources folder and maven make it packaged into the jar.
to start the app , I run
java -jar -Djava.security.krb5.conf=<localPath>/krb5.conf my-jar.jar
currently I have to give the <localPath> as the path to the file on my machine. Is there a way to refer to the file inside the jar so that I can run in any machine without creating the file file first on the machine?
things I tried so far:
give -Djava.security.krb5.conf=classpath:krb5.conf (also ./krb5.conf). Didn't work
I see most of the examples for 'how to read files from class path' refer to getClass.getResource (filename). So I tried do getClass.getResource (filename).getPath() so that I can set it as java.security.krb5.conf system property while starting the app in main class instead of passing from command line. But the string that getPath shows is something like /<diskPath>/my-jar.jar!/BOOT-INF/classes!/krb5.conf and this path is not working when I try to read the file for testing.
Create a copy of the file to the running dir on-the-fly, in main method before calling SprinApplication.run. This is what I am doing now.
try(
InputStream in = new ClassPathResource("krb5.conf").getInputStream();
OutputStream out = new FileOutputStream( new File("krb5copy.conf"));) {
IOUtils.copy(in, out);
}
System.setProperty("java.security.krb5.conf","krb5copy.conf");
If there is a solution for this question , I can see other use cases such as providing the trustore file included in jar as javax.net.ssl.trustStore etc.
give -Djava.security.krb5.conf=classpth:krb5.conf (also ./krb5.conf).
Didn't work
It's not 'classpth' it's 'classpath', actually. AND with a slash after it.
-Djava.security.krb5.conf=classpath/:krb5.conf should work.
The code that reads the krb5.conf configuration file uses FileInputStream, which requires the path to the file and doesn't "understand" classpath: prefix.
The idea below is to locate the file on the classpath and from that to get the path to the file:
ClassPathResource resource = new ClassPathResource("krb5.conf");
try
{
String fileSpec = resource.getURL().getFile();
System.setProperty("java.security.krb5.conf", fileSpec);
}
catch (IOException e)
{
// TODO handle the exception
e.printStackTrace();
}
EDIT: When packaged as SpringBoot fat JAR, trying to read the file with FileInputStream results in java.io.FileNotFoundException: file:/<path-to-jar/<jar-name>.jar!/BOOT-INF/classes!/krb5.conf (No such file or directory) :-(

How to inject a Resource from classpath in Spring?

I want to inject a file from src/main/resources like this:
#Value("classpath:myfile.txt")
private Resource res;
When I run this from eclipse it works fine.
But from a standalone folder, the file is not found:
Caused by: java.io.FileNotFoundException: class path resource [myfile.txt] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/D:/myapp/myapp-1.0.0.jar!/myfile.txt
at org.springframework.util.ResourceUtils.getFile(ResourceUtils.java:212) ~[spring-core-4.1.4.RELEASE.jar:4.1.4.RELEASE]
How can I tell spring that the file to be injected is actually in the root of the jar, not an absolute path?
Same result if I try to load it programmatically.
res = new ClassPathResource("myfile.txt");
It turned out the injection itself did work, BUT I accessed the file using res.getFile() which threw the NPE.
When just retrieving the URL and fetching the file explicit with File file = ResourceUtils.getFile(res.getURL().getFile()); it worked as expected.
Though I'm not sure wether this is a bug or works as expected.
You said this works in eclipse:
#Value("classpath:myfile.txt")
private Resource res;
Now try this in eclipse (notice the *), if it works, standalone should be ok:
#Value("classpath*:myfile.txt")
private Resource res;
When deploying outside eclipse, make sure myfile.txt is on the classpath; the best location is in the root directory where Java class file packages are located (com, org)

Listing files in project directory in Linux environment using File.listFiles() in java

String path = ".";
String files="";
File folder = new File(path);
File[] listOfFiles = folder.listFiles();
for (int i = 0; i < listOfFiles.length; i++)
{
if (listOfFiles[i].isFile())
{
files = listOfFiles[i].getName();
System.out.println("files::::::::::::"+files);
}
}
Say the above java file I saved under the path D:/spike/FileList.java.
In the above code if I run in windows platform, it will list the files under the 'spike' directory.
But when I keep this in Linux environment say the path is usr/local/apache/webapps/webtest/src/FileList.java
The result I get is files under root directory.
What I require is under the project root folder, i.e. in above case under the webtest directory.
How can I do the same. My requirement is I need to first list the files and then from the list of files I need to read sample.properties file.
I know we can hard code the path to get the same. But without hard coding how can I get the list of files under the project root folder of webapps i.e, under webtest folder in my case.
I also tried by reading the environmental variables. But the problem here is my apache folder owner is spike and not root. So when I execute System.getenv() what I get is only whatever variables the user spike has set.
But when I execute System.getenv() from any other folder whose owner is root, then I get the complete environmental variables.
So is there any way I can get the project root folder by using the above java code snippet without hard coding the path?
By the way this is a web application deployed in tomcat. First the app will read the details from the server.properties file. But Im not supposed to hard code the path as the path changes from system to system. So my intention is that the code read the properties file from the project starting folder.
This is not true, your code on Linux
prints the files in the current folder.
I just tried it.
As to tomcat, see here
What determines the current working directory of Tomcat Java process?
and/or look for similar information on the Tomcat site.
If your file sample.properties is located in the root folder, and actually is a properties-file I would try this loading the file and printing the content:
String filename = "sample.properties";
Properties properties = new Properties();
properties.load(getClass().getClassLoader().getResource(filename).openStream());
properties.list(System.out);
getClass.getClassLoader() will get the location of the rootfolder. If you skip getClassLoader you will get the folder of the package in your class.
(If you are running this in a standalone java app the properties file needs to be located in the classes folder.)
You can try with the current working directory:
String path = System.getProperty("user.dir");
But this depends where exactly is the CWD, e.g. how was this application started?
In the context of a web application, you can do (as long as you have the ServletContext object):
ServletContext application = ...
String path = application.getRealPath("/");
This will give you the root of the web application, you can navigate to the required directory from there.

Classpath Resource in Tomcat6 (Works in Jetty)

I'm having trouble with a legacy Web Application that I'm migrating to Maven3.
I need to obtain a file from the Classpath that in the directory structure is located in:
/src/main/resources/com/thinkglish/geoip/GeoIP.dat
When I create the .war file with the Maven build, I can confirm that this .dat file is located (as it should be) in:
WEB-INF/classes/com/thinkglish/geoip/GeoIP.dat
I'm trying two different approaches to get the resource from one of my classes, which implements javax.servlet.Filter:
ClassPathResource resource = new ClassPathResource("com/thinkglish/geoip/GeoIp.dat");
and
URL resource = getClass().getResource("/com/thinkglish/geoip/GeoIp.dat");
If I start the application using Maven's Jetty plugin, that works fine in both ways. However, when I deploy the application in a Tomcat and start the server, the resource cannot be located.
In the first case I get a java.io.FileNotFoundException: class path resource [com/thinkglish/geoip/GeoIp.dat] cannot be resolved to URL because it does not exist and in the second case the resource is null.
A curious thing about all this is that if I use one method or the other trying to obtain another resource from the Classpath (e.g. com/thinkglish/struts/i18n/MessageResources.properties or com/thinkglish/filter/LanguageFilter.class) it works without any problems.
Do you have any guess about this? Is it possible that the .dat extension has anything to do with this?
Edited - More data!
I added a new .properties mock file to the exact same directory in which the .dat file lives:
/src/main/resources/com/thinkglish/geoip/mock.properties
I tried to obtain it in Tomcat6 and it worked!
ClassPathResource resource = new ClassPathResource("com/thinkglish/geoip/mock.properties");
I'm starting to think that I need to do something else configuration-wise to make Tomcat6 accept the .dat file as a Classpath resource.
Thanks in advance!
I might be barking up completely the wrong tree here... but have you checked the capitalisation of GeoIP.dat / GeoIp.dat? Is Tomcat running on a case-sensitive OS?
Following should work:
String classpathLocation = "com/thinkglish/geoip/GeoIp.dat";
URL classpathResource = Thread.currentThread().getContextClassLoader().getResource(classpathLocation);
// Or:
InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream(classpathLocation);

Categories

Resources