Loading Freemarker templates from outside classpath/jar - java

i am trying to use FreeMarker to generate reports for different agents that work in my application. I looked online but couldn't find anywhere if it is possible to load the templates if they are not located in the resources folder of my project.
As my application runs from the *.jar files i tried to use:
public ReportTemplate(final String template_path)
throws TemplateException, IOException {
CFG.setDirectoryForTemplateLoading(new File("."));
CFG.setDefaultEncoding("UTF-8");
template = CFG.getTemplate(template_path);
}
and then in my conf file where i pass the template:
parameters: {
report: /../test.ftl
}
*.jar file and the template are in the same folder, but as I understand it i first need to exit the jar file, then go and get the template.
I am wondering is there an easy way to load templates for FreeMarker without putting them in the /resources/ folder of my project (that way when someone else is using the application he can design his own template and just copy it to the folder).
I would also like not to use hard coded paths such as "/tmp/", thats why I am using the "." current location path.

It's possible to load templates from pretty much anywhere, and also to load templates from multiple locations. But I suspect there's a couple of misunderstandings here.
There's only a single cfg.templateLoader property. cfg.setDirectoryForTemplateLoading(dir) is just a convenience shorthand for cfg.setTemplateLoader(new FileTemplateLoader(dir)), and cfg.setClassForTemplateLoading(...) is just a convenience shorthand for cfg.setTemplateLoader(new ClassTemplateLoader(...)). If you need to load with both mechanisms (from an arbitrary directory, and from jar-s on the Java classpath), then you need to use cfg.setTemplateLoader(new MultiTemplateLoader(new TemplateLoader[] { new FileTemplateLoader(dir), new ClassTemplateLoader(...) })). Now if you try to load foo/bar.ftl, first the FileTemplateLoader will try to load foo/bar.ftl relative to its own base directory, and if it's not found, then the ClassTemplateLoader will try to load foo/bar.ftl relative to its own base package. The two TemplateLoader-s are totally independent virtual directory trees, not aware of each other. It's just MultiTemplateLoader that overlays the two trees over each other via the fallback mechanism I have just shown.
Also note that ClassTemplateLoader is not aware of the location of the jars, or if there are jar-s involved at all. It just asks a Java ClassLoader to locate and load resources.
Also note that using new File(".") is usually a bad idea, because in most applications you have no good control over what the current working directory will be at the time the TemplateLoader is created. Usually you have an absolute path in some configuration file instead, or it's passed in as command line argument. FreeMarker doesn't care how you do it though.

Related

read / write Files in project folder

Hi I was wondering how to access files in the project folder in java/maven, i have thought about using src/main/resources, but i have been told it is a bad idea to write to files in this directory, and should only be used in configuration for the project, So i have created a new non source folder but i was wondering if there is a way to access this file in java without giving an absolute path, as i need to use it in different env. any help or other suitable suggestions would be great here thanks. i will be writing to the files at runtime.
EDIT:
i am using this to acces the file:
private static final String ACTUAL_VALUES ="verification/actualCounterValues.csv";
where verification is a folder i have created in my project
As i understand you, your goal is to access a file from within your app, without hardcoding a relative path because you're going to run it on different environments.
The first thing you may have to solve is to decouple the file-reference from your app - because if you move your app it must adapt to the new environment.
You may solve that by putting an absolute file-reference into the system-environment (which is accessible through the System.getenv() method). Another way could be to deliver the file-path as command-line-argument.
After that you have to specify when which running instance of your app will access the file. If your application runs separated in the maven and a production environment - everything is fine with using relative paths in the maven-project. The production-app will then generate and use its own file in its environment.
If they must share the file, you have to provide physical access from both environments to that file-path, after that you may access that file with separate absolute paths (delivered through cli-args or system-properties) or with "hard coded" relative paths, which access a file-link (which point to that absolute file).
But i must discourage you from using any hardcoded configuration-specific variables for ongoing maintenance reasons.
And if these two application-instances will access both one single file, you should also be aware of possible concurrency difficulties (especially in the filesystem - see that post).

Why does an image path no longer work once I compile my java files into a jar file?

I have a relatively basic java program which uses a system tray icon. The path I was using while writing the code is as follows "../images/logo.png". However, when I compile it into a jar file, the image does not show up in the system tray. Instead, if I change the path to "./images/logo.png", then the image shows up in the system tray when it's in the jar file form, but not while I'm testing.
It's not a major issue. However, I am curious to know why this inconsistency occurs.
When you package your program into a .jar file, your build is most likely copying the image into the same directory as the .jar file. However, when debugging in your ide, your image file lies one directory below.
Another possibility is that you are simply setting your Working Directly differently in the two scenarios.
Incidentally, you might be interested in embedding the image in your jar file, see:
https://stackoverflow.com/a/1096491/24954
This answer depends on two things. If the image file is embedded or not.
Embedded Resource
Once you have Jar'ed your application and the images are emebbed inside the application, normal file access methods will no longer work.
Trying to do something like...
new ImageIcon("../images/logo.png");
or
new File("../images/logo.png");
Won't work. This is because the resource is no longer a file within the context of the file system (it's actually a Zip entry in the Jar).
Instead, you need to use Class#getResource which will return a URL to the embedded resource.
new ImageIcon(getClass().getResource("../images/logo.png"));
Will work better. In general though, it is recommended to use an absolute path to the resources new ImageIcon(getClass().getResource("/images/logo.png")); as it's generally more difficult to break (IMHO)
External Resource
The path to the image is relative to the execution point of the application.
In development, you may have had to move up a directory (out of the src folder presumably) to find the image resource. This will mean that you will need to store you Jar file in a folder that would require it step up one level before it could find the image resource.
If you can, it's generally better to embedded the resource within the Jar where possible. It makes it easier to deploy as you reduce the number of files you need to package and makes it (a little) harder for the user to mess with it ;)

How to reference a file in the source dir from any Java code?

Suppose I had a directory containing resource files stored somewhere within the "src" source directory, containing things like templates, config files, etc.
I'm aware that from a Servlet I can access files by name like:
File file = new File(ServletContact.getResource("some/namespace/filename.txt").getPath());
And from a non-Servlet I can do:
File file = new File(Object.class.getResource("some/namespace/filename.txt").getPath());
But the problem is that I have code that needs to access these resource files and can be run independent of the runtime environment. e.g. Some code uses templates from within a servlet (under Tomcat 7). Other code runs as a Quartz background job and works with templates. If I try the Object.class.getResource() method in a Tomcat servlet, it returns null.
How can I access resources files in a safe way regardless of runtime environment, app engine, etc.?
To read file from classpath you can use:
getClass().getClassLoader().getResourceAsStream("path/to/resource");
Also there is simple and useful Spring utility ClassPathResource class:
Resource resource = new ClassPathResource("path/to/resource");
I would use any class (e.g. domain class) from your project, use getClassLoader() or getContextClassloader() and provide the path to your resource. Should work.

File and bundleresource:// URLs

I've been breaking my head over this for quite a while now and cant find a solution for this problem:
I have an Eclipse RCP application that uses a custom library packaged as jar. From the plugin, i am calling a method within the jar.
Within this method, i am "getting" a resource using this.class.getResource(relPath), whereas relPath is a hardcoded relative path to a file i need. This returns me an URL which i can use to construct a File.
Now, this works perfectly if i am not calling this method from the plugin, but from a simple Java-Program.
The difference: Eclipse RCP's classloader returns an URL of protocol bundleresource:// which is not supported by File, whereas when running a simple Java-program, a file://-URL is returned which is completely fine to construct a File.
I am aware of the FileLocator-class of the Eclipse SDK (which resolves bundleresource-URLs to file-URLs), but i cannot use it within the library because i dont want to tie it to the Eclipse RCP platform - it should be possible to use this lib from non-Eclipse-RCP sources as well.
Anyone any idea on how i can load this resource from a relative path in a manner that will work both when the method is called from an Eclipse RCP-Plugin or any other client?
I need to construct a File on the directory of this relative path to search for files within. I am completely stuck on this...
UPDATE: If there is a possibility other than using File#list() to get directory contents this would already help me..
any hints greatly appreciated,
Couldn't you simply invert the dependency. I.e., your module retrieving the resource as URL defines an interface
interface Locator { URL resolve(URL url); }
and you can use a default implementation
class StandaloneLocator implements Locator {
public URL resolve(URL url) { return url; }
}
In case of Eclipse, this default locator is to be replaced by
class EclipseLocator implements Locator {
public URL resolve(URL url) { return FileLocator.resolve(url); }
}
Now, your library has no dependencies to Eclipse, and you can still use the FileLocator. Since you won't get any bundleresource-URLs w/o Eclipse, this should work.
Cheers,
Jens
That is not possible to enumerate files in jar file using methods from Class. You either need to create resourcelist file which will contain all your resources names, or open jar file like zip archive and enumerate files like in zip archive. File class can not handle protocols other than file://. If your rescource is in jar file, you should use Url class and get stream using Url.openSteram method to get file contents.
UPD regarding running simple java application: you probably does not pack it into jar file, so your classes and resources are placed in file system and not in archive. That is why you get file:// protocol. If you pack into jar file, protocol will not be file:// it will be jar:// (not sure about exact protocol name).

Java (maven web app), getting full file path for file in resources folder?

I'm working with a project that is setup using the standard Maven directory structure so I have a folder called "resources" and within this I have made a folder called "fonts" and then put a file in it. I need to pass in the full String file path (of a file that is located, within my project structure, at resources/fonts/somefont.ttf) to an object I am using, from a 3rd party library, as below, I have searched on this for a while but have become a bit confused as to the proper way to do this. I have tried as below but it isn't able to find it. I looked at using ResourceBundle but that seemed to involve making an actual File object when I just need the path to pass into a method like the one below (don't have the actual method call in front of me so just giving an example from my memory):
FontFactory.somemethod("resources/fonts/somefont.ttf");
I had thought there was a way, with a project with standard Maven directory structure to get a file from the resource folder without having to use the full relative path from the class / package. Any advice on this is greatly appreciated.
I don't want to use a hard-coded path since different developers who work on the project have different setups and I want to include this as part of the project so that they get it directly when they checkout the project source.
This is for a web application (Struts 1.3 app) and when I look into the exploded WAR file (which I am running the project off of through Tomcat), the file is at:
<Exploded war dir>/resources/fonts/somefont.ttf
Code:
import java.io.File;
import org.springframework.core.io.*;
public String getFontFilePath(String classpathRelativePath) {
Resource rsrc = new ClassPathResource(classpathRelativePath);
return rsrc.getFile().getAbsolutePath();
}
In your case, classpathRelativePath would be something like "/resources/fonts/somefont.ttf".
You can use the below mentioned to get the path of the file:
String fileName = "/filename.extension"; //use forward slash to recognize your file
String path = this.getClass().getResource(fileName).toString();
use/pass the path to your methods.
If your resources directory is in the root of your war, that means resources/fonts/somefont.ttf would be a "virtual path" where that file is available. You can get the "real path"--the absolute file system path--from the ServletContext. Note (in the docs) that this only works if the WAR is exploded. If your container runs the app from the war file without expanding it, this method won't work.
You can look up the answer to the question on similar lines which I had
Loading XML Files during Maven Test run
The answer given by BobG should work. Though you need to keep in mind that path for the resource file is relative to path of the current class. Both resources and java source files are in classpath

Categories