java.io.FileNotFoundException when using tomcat - java

I have an application running fine on localhost but I am having issues when It is deployed on tomcat
The code I am using to read the file is :
File jasperFile = new File(getClass().getClassLoader().getResource("reports/Header.jasper").getFile());
I get this error in catalina :
net.sf.jasperreports.engine.JRException: java.io.FileNotFoundException: file:/usr/local/apache-tomcat9/webapps/com.peek.facture.server/WEB-INF/lib/facture.server-1.0.0-SNAPSHOT.jar!/reports/Header.jasper
What triggers me is the "!" at the end of the jar name, where does it come from?
Also I have tried to download the jar, extract it, and my Header.jasper is correctly in the resources/reports/ folder

When you run on your local a stand-alone physical file Header.jasper exists (you can physically see it when you browse the reports directory).
However when you deploy to a tomcat server, that stand-alone physical file no longer exists. Instead, if you set-up your build correctly, when you open up your jar (facture.server-1.0.0-SNAPSHOT.jar), there should be a directory called reports in it with the file Header.jasper within that directory.
So when your try get a resource via getClass().getClassLoader().getResource(...).getFile() you are actually trying to access a stand-alone physical file. Instead you need to get the resource as an InputStream and then work with if from there...
InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("reports/Header.jasper");
When working with resources, it's always better to rather access them this way. Especially if you are planning to deploy anywhere with a single artifact, because your resources should be packaged in with your artifact.

Related

Can not load properties file on classpath; [java, jboss, maven, spring]

I have a properties file called app.properties that is correctly put in src/main/resources/app.properties.
In the WAR file it is correctly located in \WEB-INF\classes.
In Standalone mode in my local environment (windows) and standalone mode on a linux test server, the WAR file starts up correctly reading my properties file.
In Jboss Domain mode on another linux server, using the exact same WAR file, I get error file not found app.properties. It is indeed there.
Other than domain mode being the difference between the two servers, the first test server jboss is installed under root and running as root. The other server is running as a user that has read and execute access.
I've thoroughly debugged the code with print statements and im 99% sure it is not a code issue, any ideas what in jboss domain mode may be causing the problem of not being able to read the properties file on the classpath?
Thanks in advance.
Relevant parts of code
MutablePropertySources sources = new MutablePropertySources();
sources.addLast(getEncryptablePropertiesSource(new ClassPathResource("app.properties")));
partial method
private EncryptablePropertiesPropertySource getEncryptablePropertiesSource(Resource propsResource) throws IOException{
//don't use file system resource because property files may be in a jar
System.out.println(">>>> in getEncryptablePropertiesSource filename is :");
System.out.println(propsResource.getFilename());
System.out.print(">>>> URL is: ");
System.out.println(propsResource.getURL());
The last System out print statement throws the error in the 2nd test environment, does not cause problems in any other environment.
If your ClassPathResource is the class from Spring:
public class ClassPathResource extends AbstractFileResolvingResource
Resource implementation for class path resources. Uses either a given
ClassLoader or a given Class for loading resources.
Supports resolution as java.io.File if the class path resource resides
in the file system, but not for resources in a JAR. Always supports
resolution as URL.
Therefore I don't think you can use it in your case.
Have you tried using one of the following methods?
ClassLoader.getResource(String name)
ClassLoader.getResourceAsStream(String name)

Using ResourceUtils.getFile to read a file from classpath in Heroku environment

I'm running a Spring Boot application in Heroku, using Maven to manage the build lifecycle.
During the initialisation phase of my application, I want to read a file packaged into my JAR file.
To manage to get the content of the file I'm using the Spring utility class ResourceUtils, and I'm expressing the path of the file using the special prefix classpath:.
The code I'm using looks like this:
String pathToMyFile = "classpath:com/myapp/myFile.test"
List<String> fileLines = Files.readLines(ResourceUtils.getFile(pathToMyFile), IOConstants.DEFAULT_CHARSET_TYPE);
This code works as expected when I execute the application in my local machine.
But when I push my application to Heroku I'm getting the following error:
Caused by: java.io.FileNotFoundException: class path resource [com/myapp/myFile.test]
cannot be resolved to absolute file path because it does not reside in the
file system: jar:file:/app/target/myapp.jar!/com/myapp/myFile.test
I've run a heroku run bash and I've checked that the file is just where it should be (inside the jar).
Moreover, according to the error trace, Spring locates the file, because it transform the path from classpath:com/myapp/myFile.test to jar:file:/app/target/myapp.jar!/com/myapp/myFile.test
I suspect that when you are running locally, it is picking up the file on the classpath from an exploded JAR file (i.e. as a regular file on the filesystem).
On Heroku, it is in the JAR file, which means it is not a regular file, and must be read as an input stream, which might look like this:
ClassLoader cl = this.getClass().getClassLoader();
InputStream inputStream = cl.getResourceAsStream(pathToMyFile);
Then you might use a BufferedReader to read the lines. But maybe ResourceUtils has a better method.
You can probably reproduce the problem locally by running the same command that's in your Profile.

Getting reources path creates weird path (in jar works)

I've got some weird problem. I get access to my resources files like this:
File xmlFile = new File(getClass().getResource(xmlPath).getPath());
Where xmlPath is "/META-INF/file.xml".
When I run from Eclipse, everything works fine. Unfortunately, when I pack everything to jnlp file, upload with my web app on tomcat (from where I download all jar's by jnlp) it stops work.
When I run my jnlp, it downloads all jar's like it should and fails to start. Throwing this exception:
java.io.FileNotFoundException: C:\Users\A050868\Desktop\http:\address:port\webapp\downloads\lib\package.jar!\META-INF\componentContext.xml (The filename, directory name, or volume label syntax is incorrect)
How can I get access to my file, which is in resources/META-INF folder, in cached locale jar copy? For now it seems, like Java try get access to jar on server side - no this local, downloaded by jnlp.
Any ideas?
All the files are packed together in your jnlp file. They don't to exist as individual files on filesystem when you port your package.
That said, they are available on the classpath. You can access the content of your package using the appropriate classloader.
getClass().getClassLoader().getResourceAsStream(...)
This may help you

finding static file in jar

I am trying to use a jar file which itself is a web application in another web project. In my jar which i have created using eclipse's export to jar functionality, I have stored a csv file in a folder. To use relative paths in the code in the jar I access it using
MyClass.class.getResource(ApplicationConstants.ALIASESFILE).getPath();
and this works fine when I deploy (glassfish) and use the project as a separate application. But when I am using the same from within another project, it gives a path as shown below
D:\javaProjects\AutomodeGS_Prachi\lib\internal\RESTWSGS.jar!\aliases\aliases.csv
I am getting a file notfound exception.What could be wrong?
The getResource() method is returning a "jar:" URL. The path component of that URL is not a normal filesystem pathname, and can't be opened directly using Java's file classes.
The simple way to do this is to use Class.getResourceAsStream(...) to open the stream. If you need an "identifier" for the JAR entry, use Class.getResource(...), but then open the stream using URL.openStream().
This works fine from glassfish may be because glassfish has exploded jar on file system so that your csv file is acutually a file to the file system,
if you try to read it from another project it fails because the jar containing your file is in classpath that is fine, but the csv file is under jar file and it is no longer a File
You can read it as Stream
InputStream is = MyClass.class.getResourceAsStream(ApplicationConstants.ALIASESFILE);

Locating created file with Java EE and Tomcat

I have created a dynamic web project, and use Apache Tomcat as a server.
In my servlet I'm creating a text file and want to reuse that in a JSP. However they are by default created in the installation folder of Eclipse when I do something as simple as the following:
File f = new file("test.txt").
I don't know why this happens. Is there a way to create the file in the WebContent directory as I want to make that file available for download in my JSP.
Java has a concept of the "current directory". When you start an application via Eclipse, this may indeed point to your installation directory. If you don't specify any path, a file will be created in this current directory. Hence the reason why your test.txt ends up there.
The WebContent directory is a something that is specific to Eclipse. Your code should not depend on putting anything there. You only start your application via Eclipse when you're developing it, not when you're deploying it to a live server.
The content of this directory will become the root of your .war, which is a well known location independent of how you start & deploy you app, BUT you still cannot depend on writing anything to this location at run-time. You might deploy your application as a packaged .war (likely for live deployments) or you may deploy your application unpackaged but then your application server may simply not pick up any changes done at run-time.
What you can do if you are sure your application only runs on a single server is writing the files to a well known location on your file system, such as /tmp, or /var/yourapp/files, etc. The code serving up those files can then pick them up from that location.
If you want to play it 100% safe according to the Java EE rules, you'd store your files on something like an FTP server that has a configurable address. Technically your war could be shipped between nodes on a cluster and requests could end up going to different machines, so depending on a local filesystem wouldn't work then.
Executing this statement this.getServletContext().getRealPath (""), you'll obtain the path where Tomcat WebServer is pointing at at runtime. You could add a folder "MyFolder" and call this statement:
new File(this.getServletContext().getRealPath ("") + "/MyFolder/test.txt");
Anyway, the default path looks something like:
...\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\<NameOfYourProject>
Note that when you create a new file, it won't appear in your immediate workspace (check the .metadata path), unless you change the runtime location tomcat should point at.

Categories