Mustache throws "File not under root" exception in NetBeans servlet - java

Edit: I solved my problem. (See below.)
The problem
I'm new to NetBeans, and I'm having a problem that involves loading a resource to my servlet application, which runs via NetBeans using Tomcat as the server. Everything is fine until I try to build my response using the Mustache template library (in Java). At that point, an exception is thrown:
com.github.mustachejava.MustacheException: File not under root: /opt/catalina/bin
This exception is thrown right at the point in my code where I try to compile the template file. I feed the path to the resource (the template file) to the compile method of the MustacheFactory. My code looks like this:
MustacheFactory mf = new DefaultMustacheFactory();
Mustache mustache = mf.compile(getFormTemplatePath());
My research
I took a look at the Mustache code, and as best as I can tell, here is what's happening. Mustache does a security check when it loads the resource, trying to ensure that the resource is under the application's root in the file system. Because NetBeans is working some kind of magic to run the code on the Tomcat server, while the project's code is actually somewhere else on the file system, Mustache thinks something fishy is going on.
In other words, it can find the file; it just doesn't like where it's finding it. It seems like Mustache takes /opt/catalina/bin as the application's root, while the template file is actually at a path more like: ~/NetBeansProjects/MyProject/WEB-INF/template_file.mst.
The Mustache code looks like this (just so you can check my reasoning):
try {
// Check to make sure that the file is under the file root or current directory.
// Without this check you might accidentally open a security whole when exposing
// mustache templates to end users.
File checkRoot = fileRoot == null ? new File("").getCanonicalFile() : fileRoot.getCanonicalFile();
File parent = file.getCanonicalFile();
while ((parent = parent.getParentFile()) != null) {
if (parent.equals(checkRoot)) break;
}
if (parent == null) {
throw new MustacheException("File not under root: " + checkRoot.getAbsolutePath());
}
// [Try-catch block continues...]
I found the Mustache code online at the following URL:
https://github.com/spullara/mustache.java/blob/00bd13145f30156cd39aaad7ab046b46b1315275/compiler/src/main/java/com/github/mustachejava/resolver/FileSystemResolver.java#L50
My hypothesized solution
I'm guessing there must be some way to configure the application in NetBeans, when I'm choosing and configuring the server, to reconcile this issue. What I have tried is googling variations of Mustache NetBeans servlet "File not under root" exception and so forth, and nothing much comes up. I'm guessing that I don't even know enough about NetBeans to know what key words I should be searching with. It's even possible that I've found the solution, but don't recognize it when I see it.
Does anybody know what I might try? Thanks.

you can use the other overload API instead
Mustache compile(Reader reader, String name);
just like this and you can prefer to put the mustache template file anywhere
File f = new File(templateFilePath);
Mustache mustache = mf.compile(new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8")),f.getName());

Where to put the template file?
I solved this on my own, though I solved it by doing something better with the template file. Originally, I was putting the template file in the WEB-INF directory and then building the path to the file using the servlet context. That doesn't seem like best practice.
Taking another look at the Mustache source code I realized that Mustache first tries to use the classloader to get the file. If you let Mustache do it in its preferred way, you don't need to give the full path, only the file's name. But the classloader only looks in certain places, the WEB-INF/lib directory being one. A number of people on the Web recommend putting the Mustache template in the WEB-INF/lib directory.
Since mine is a Maven project, I moved my template file to the src/main/resources directory. (In NetBeans, this is "Other Sources" in the Projects pane.) At build, Maven takes anything in there and dumps it into the WEB-INF/lib. I then only had to change my source code to use the file name, instead of the real path to the file (as I had been doing). Everything works.
So, as far as I'm concerned, my problem stemmed from putting the template file in what turns out to be an awkward location for Mustache. If anyone has a better idea, or anything else to add, I'm all ears.

Related

Same code behaving differently on two different packaging

I have a set of codes which are common for two different products, but a part of the code is behaving differently for each product
URL wsdlURL = IntegrationLandscapeService.class.getClassLoader().getResource("IntegrationLandscapeService.wsdl");
For One set up it is giving absolute path and for the other its giving relative path and this is leading to problems, my requirement is to get absolute path for the issue.
Packaging:
Code flow:
The call is made from the Main Class File and from there CommonCode in common code it is looking for the WSDL located in LandScapeService.jar
Update:
The next line of the code is
IntegrationLandscapeService landscapeService = new IntegrationLandscapeService(wsdlURL);
but I get the below error
failed [Failed to access the WSDL at: jar:file:/
tracker.jar!/lib/t24-IF_IntegrationLandscapeService-IntegrationLandscapeService-jwc.jar!/IntegrationLandscapeService.wsdl
.It failed with:
\tracker.jar (The system cannot find the file specified).]
Screen Shot of Jar
The error shows two '!' in the path which indicates the resource is in an embedded/nested/inner jar-file. A product that uses the fat/bundled-jar approach (where one jar-file contains other jar-files) will need some trickery to load classes and resources from the embedded jar-files. You can read about it at http://www.jdotsoft.com/JarClassLoader.php (*)
In any case, there is not much you can do about it since loading resources from embedded jars is not supported natively by Java. The implementation providing the "trickery" I mentioned above will need to fix that (and some do it better than others, see the link above).
The other product with a Par-file indicates the use of OSGi which only requires proper configuration to keep resource-loading working. There is an answer here that explains your situation and solution options.
(*) Spring-boot also has some good documentation and a solution, but I have not tried using the solution with a non-Spring application. See https://docs.spring.io/spring-boot/docs/current/reference/html/executable-jar.html for more information.
You can use getAbsolutePath
File file = new File(url.getPath());
String path = file.getAbsolutePath();
Isn't that what you are looking for?
This is because the files inside the JAR are not treated as regular files, as they are not expanded and not available directly to file explorer.
In Jar, if the files are referred, you will get the path from the root of the JAR file.
Please make sure you have the classpath entry for the Jar location. This will help to find the resource. Otherwise, try the following code(not sure whether it will work in your case, give it a try).
String resource = "/com/example/IntegrationLandscapeService.wsdl"; //package structure of the file
URL res = IntegrationLandscapeService.class.getResource(resource);
Refer this answer to understand more Stack Overflow comment

Behavior between Runnable .jar and Eclipse run is very different

I am using an XML document as a template for multiple, similar documents (monthly reports which are organized identically). I was struggling to find the most generic path to the file. I came up with:
File f1 = new File("src/Statements/TemplateStatement.xml");
where /Statements/ is a folder under the src tab in Eclipse as if it were just another package.
Then:
File TemplateStatement = new File(f1.getAbsolutePath());
if (TemplateStatement.exists()) {
// ...do some stuff
} else {
JOptionPane.showMessageDialog(null, null,
"ERROR: Transaction template not found.", JOptionPane.OK_CANCEL_OPTION);
System.exit(0);
}
When running from Eclipse, it works great and my stuff gets done. When running as a .jar on my desktop (same machine and file system), I hit the else clause every time. I suspect I am missing a very basic yet important property of how jars package up the workspace and run it (as in there is no src directory associated with it anymore?).
I have had no luck finding examples or explanations on how to find the path, access, read, write, copy, etc. files from jarred applications. I really want to avoid hard-coding a full path as it may be the case the code will run on various machines. Any suggestions or pointers would be appreciated.
I've just encounted a similar problem, and it was caused by the java.io.FileReader function which uses platform default encoding.
As for my situation, in Runnable .jar running, java.io.FileReader uses ISO-8859-1 encoding, while in Eclipse it uses UTF-8 encoding. Replacing
new FileReader(filepath)
with
new InputStreamReader(new FileInputStream(filepath), "UTF-8")
solves my problem.

Load files dynamically in multiple environments

so I am in the process of making a small application.
Right now, the project works fine. I am running it through an IDE. The problem comes about when trying to run the project as a jar - which is the end result. Right now, it fails to properly load the required files (classes and simple ASCII files).
The method I am using is one based off of:
final Enumeration<URL> paths = CLASS_LOADER.getResources("");
Where CLASS_LOADER is an instance of class.getClassLoader().
This works great when not inside a jar. Inside a jar though, it seems to fail horribly. For example, in the code above, paths would be empty.
I am assuming that the fault is that the files are all within a jar - the same jar to be precise.
The class path for the manifest file is blank at the moment.
If it helps, I have two tasks that require loading files.
I need to create a list of all files that are a subclass of
another class.
I need to load a list of language files (all of
which are in the same directory).
If you need anything else to help debug this problem or provide a solution - let me know. Thanks for reading this!
For ClassLoader.getResources() to work you need to feed a path relative to the jar root. If you want to search the jar then ClassLoader public API won't help you. You have to use custom code based on java.util.jar.JarFile, like the one here.

Path resolution in eclipse package structure

This is a very simple question for many of you reading this, but it's quite new for me.
Here is a screenshot for my eclipse
When i run this program i get java.io.FileNotFoundException: queries.xml (The system cannot find the file specified) i tried ../../../queries.xml but that is also not working. I really don't understand when to use ../ because it means go 1 step back in dir, and in some cases it works, can anyone explain this? Also how can I refer to queries.xml here. Thanks
Note: I might even use this code on a linux box
I assume it is compiling your code into a build or classes folder, and running it from there...
Have you tried the traditional Java way for doing this:
def query = new XmlSlurper().parse( GroovySlurping.class.getResourceAsStream( '/queries.xml' ) )
Assuming the build step is copying the xml into the build folder, I believe that should work
I don't use Eclipse though, so can't be 100% sure...
Try
file = new File("src/org/ars/groovy/queries.xml");
To check the actual working directory of eclipse you can use
File f = new File(".");
System.out.println(f.getAbsolutePath());
You could try using a property file to store the path of the xml files.
This way you can place the xml files in any location, and simply change the property file.
This will not require a change/recompilation of code.
This would mean you will only need to hardcode the path of the property file.
If you prefer not hardcoding the path of the property file, then you could pass it as an argument during startup in your server setup file. (in tomcat web.xml). Every server will have an equivalent setup file where you could specify the path of the property file.
Alternatively you could specify the path of the xml in this same file, if you don't want to use property files.
This link will show you an example of reading from property files.
http://www.zparacha.com/how-to-read-properties-file-in-java/

How should I discover test-resource files in a Maven-managed Java project?

I have a project that uses the normal Maven structure, e.g.
module
\ src
\ main
- java
- resources
\ test
- java
- resources
etc. Under test/resources, I'd like to keep a set of test input files for a parser I'm writing, then run all files in the directory through the test suite. As written now, the test code works from the command line, but fails when run through the Eclipse JUnit plugin:
File file = new File("src/test/resources");
file.list();
(I'm actually using a FilenameFilter, but I'm trying to simplify.)
The problem, after poking through the unit test with a debugger, turns out to be that the File I'm constructing points to /path/to/workspace/myproj/src/test/resources, whereas the actual files reside in /path/to/workspace/myproj/modulename/src/test/resources (it's a Maven multi-module project). Apparently, this isn't a problem when running mvn test from the command line.
I guess my question is two-fold: one, am I doing this wrong? I see a lot of people using the class loader to discover resources, as in this question, but I don't want all the resources of a particular type, just one directory under test/resources. Two, if this isn't a terrible idea in the first place, do I have a configuration error (e.g. it "should" work)? Is it Eclipse's fault, a Maven problem, or what?
One trick would be to place a file in resources with a known name, get the URI of this file through the classloader, then construct a File from this URI, then get the parent, and list() the contents of that directory. Kind of a hack, but it should work.
So here's what the code should look like, but place a file called MY_TEST_FILE (or whatever) in test/src/resources
URL myTestURL = ClassLoader.getSystemResource("MY_TEST_FILE");
File myFile = new File(myTestURL.toURI());
File myTestDir = myFile.getParentFile();
Then you have access to the directory you're looking for.
That said, I'd be surprised if there's not a more 'maven-y' way to do it..
Just for completeness, wanted to point out the way to get this without having to grab the current instance of the ClassLoader, using ClassLoader#getSystemResource. This example does the work without having to place a file at the top.
//Obtains the folder of /src/test/resources
URL url = ClassLoader.getSystemResource("");
File folder = new File(url.toURI());
//List contents...
Try this?
1)put test data files into the same package structure as you test classes. That is, if you have a test class named Apple in src/test/java/com/fruits, you test data file will be in src/resources/java/com/fruits.
2) When the files are compiled both the class and the data file should be in target/test-classes/com/fruits. If this is the case, in you code, you can obtain the file this way "this.getClass().getResourceAsStream("myFile")"
put desired resource into /src/test/resources/lipsum.pdf
find it's full path using
String fileName = ClassLoader.getSystemResource("lipsum.pdf").getFile();

Categories

Resources