I am integrating a FMPP transformation into our Java code base. For this, I am using the FMPP Java API. For practical reasons, I have two separate directories:
one which contains the template: <absolute path template>/template.ftlx
one which contains the data: <absolute path data>/data.xml
This somehow complicates things, as I have to work with absolute paths here. Typically, the data is inside the template directory (together with a ignoredir.fmpp file). However, in our application, the data is coming from an external source (it is uploadable via a REST API), while the template is in the classpath. This also means that the data directory isn't static.
I am struggling to define all this and get the transformation happening via the Java API. Currently, I have the following:
Settings s = new Settings(new File("."));
s.set(Settings.NAME_SOURCES, new File("<absolute path template>/template.ftlx").getAbsolutePath());
s.set(Settings.NAME_OUTPUT_FILE, new File("<absolute path output>/output.xml").getAbsolutePath());
s.execute();
The code snippet above is not complete, as I have to add the data. There are the Settings.NAME_DATA and Settings.NAME_DATA_ROOT properties, but I can't get it working. I tried setting Settings.NAME_DATA_ROOT as following:
s.set(Settings.NAME_DATA_ROOT, new File("<absolute path data>").getAbsolutePath());
Then, I get the exception that FreeMarker cannot find my data:
The following has evaluated to null or missing:
==> d [in template "template.ftlx" at line 4, column 12]
In the template, I simply do:
<#list d.items>...</#list>
This makes sense that this would not work, as I did nowhere define that the data should be accessible via the d. hash (which I am doing below in config.fmpp). But I don't know how to define that properly via Settings.NAME_DATA and/or Settings.NAME_DATA_ROOT.
How can I inject my data file into all this? It should get the key d, so I can refer to d. in the template.
reference
Just as reference, if I create the following config.fmpp file in <absolute path config>, put the data.xml data file in directory <absolute path data> and call s.load(new File("<absolute path config>/config.fmpp")) before s.execute() above, everything is working fine.
data: {
d: xml(<absolute path data>/data.xml)
}
All I have to figure out is doing this in a dynamic fashion via the Java API. I cannot use config.fmpp for this, as the location of the data isn't static (and, as far as I know, config.fmpp is not parametrizable).
working solution, with doubts
After some code reading, I got it working if I do the following:
Settings s = new Settings(new File("."));
s.set(Settings.NAME_SOURCES, new File("<absolute path template>/template.ftlx").getAbsolutePath());
s.set(Settings.NAME_OUTPUT_FILE, new File("<absolute path output>/output.xml").getAbsolutePath());
s.set(Settings.NAME_DATA, "{d:xml(<absolute path output>/data.xml)}");
s.execute();
Here, we pass {configuration:xml(<absolute path output>/data.xml)} as a TDD to the NAME_DATA property. Is this the way to go? It "feels" strange to construct a textual definition in our code. Is there a way to do this in pure Java?
Related
(Sorry if this is simple; this is my first post)
Is the groovy/grails asset pipeline modifiable at runtime?
Problem: I am creating an application where users create the objects. The objects are stored as text files so that only the necessary objects are built at runtime. Currently, the text file includes a string which represents the filename of the image. The plan was to have these images stored in assets/images/ as this works best for later displaying the object. However, now I am running into issues with saving files to assets/images/ at run time, and I can't even figure out if this is possible. *Displaying images already works in the way I require if I drag and drop the images into the desired folder, however I need a way for the controller to put the image there instead. The relevant section of controller code:
def folder = new File("languageDevelopment/grails-app/assets/images/")
//println folder
def f = request.getFile('keyImage');
if (f.empty)
{
flash.message = 'file cannot be empty'
render(view: 'create')
return
}
f.transferTo(folder)
The error I'm receiving is a fileNotFoundException
"/var/folders/9c/0brqct9j6pj4j85wnc5zljvc0000gn/T/languageDevelopment/grails-app/assets/images (No such file or directory)"
on f.transferTo(folder)
What is the section it is adding to the beginning of my "folder" object?
Thanks in advance. If you need more information or have a suggestion to a different route please let me know!
new File("languageDevelopment/grails-app/assets/images/")
This folder is present only in your sources
After deployment it will looks like "/PATH-TO-TOMCAT/webapps/ROOT/assets/" if you use tomcat.
Also asset/images, asset/font etc. will be merged to assets folder.
If you'd like to store temporary files you can create some directory under src/resources folder.
For example "src/resources/images"
And you can get access to this folder from classloader:
this.class.classLoader.getResource('images/someImage.png').path
I use Velocity in order to load email templates. Those templates are first downloaded from the FTP server and then saved as temporary files.
However, when I try to load the template I get an exception:
org.apache.velocity.exception.ResourceNotFoundException: Unable to find resource 'C:\Users\someUsername\AppData\Local\Temp\template1526050996884865454.html'
And I'm sure the file is there and it's not damaged.
That's how I try to load the template:
template = velocityEngine.getTemplate(tempFile.getCanonicalPath());
Here's the velocity.properties file that I load (and I've checked that the properties are properly initialized!)
file.resource.loader.class=org.apache.velocity.runtime.resource.loader.FileResourceLoader
file.resource.loader=file
file.resource.loader.path=.
So where lies the problem? Is it because AppData folder is hidden by default?
I think there's a design flaw in the Velocity FileResourceLoader. Basically if your file.resource.loader.path is anything other than an empty string, it'll mangle any absolute paths handed to it as the file. Additionally it has Unix/Linux-specific code to "nip off" (paraphrasing the actual code comment) an absolute file-path handed to it (Giving a broken absolute path re-rooted to the current path setting).
Solution 1:
Set the file.resource.loader.path to an empty string (prior to init()) and use absolute file-paths as the file parameter
ve.setProperty("file.resource.loader.path", "");
ve.init();
Template template = ve.getTemplate("C:\\Users\\someUsername\\AppData\\Local\\Temp\\template1526050996884865454.html");
Solution 2: Set the path to be the common root for your temp files and only hand it paths relative to that:
ve.setProperty("file.resource.loader.path", "C:\\Users\\someUsername\\AppData\\Local\\Temp");
ve.init();
Template template = ve.getTemplate("template1526050996884865454.html");
Ultimately I think the FileResourceLoader class would be better if it detected any absolute path handed to it as a file-name and not try to mash the path setting into it.
In addition to #MOles's answer, there is a third solution.
Solution 3: Configure more than one file resource loader: one for absolute resources and one for relative ones. Something like this:
resource.loader=absolute-file, relative-file
absolute-file.resource.loader.class=org.apache.velocity.runtime.resource.loader.FileResourceLoader
absolute-file.resource.loader.path=
relative-file.resource.loader.class=org.apache.velocity.runtime.resource.loader.FileResourceLoader
relative-file.resource.loader.path=.
This will allow files to be loaded either relatively or absolutely, since FileResourceLoader evidently gets confused when you try to use a single instance for either type of path.
In my TestClass I want to read the txt-file. I am always very confused how I should go about getting a reference to the txt-file though. The example I dug out of the internet suggested using a BufferedReader which requires a Path object to instantiate. I thought I'd create a File object and invoke it's .toPath(). But now how do I instantiate my File object? The least scary of its constructors require a string, but which string?
The easiest way to reference the file path within the scope of your project would be to use the System properties. Using the below value would return to you the users current working directory. Something like this would do the trick:
File file = new File (System.getProperty ("user.dir") + "/" + path_to_txt_file);
Depending on your system you may need to modify the delimiter.
New to Java. I am building a Java HTTP server (no special libraries allowed). There are certain files I need to serve (templates is what I call them) and I was serving them up using this piece of code:
this.getClass().getResourceAsStream("/http/templates/404.html")
And including them in my .jar. This was working. (I realize I was reading them as an input stream.)
Now I want to store all of my files (as File type) for templates, regular files, redirects in a hashmap that looks like this: url -> file. The I have a Response class that serves up the files.
This works for everything except my templates. If I try to insert the getResource code in the hashmap, I get an error in my Response class.
This is my code that I am using to build my hashmap:
new File(this.getClass().getResource("/http/templates/404.html").getFile())
This is the error I'm getting:
Exception in thread "main" java.io.FileNotFoundException: file:/Users/Kelly/Desktop/Java_HTTP_Server/build/jar/server.jar!/http/templates/404.html (No such file or directory)
I ran this command and can see the templates in my jar:
jar tf server.jar
Where is my thinking going wrong? I think I'm missing a piece to the puzzle.
UPDATE: Here's a slice of what I get when I run the last command above...so I think I have the path to the file correctly?
http/server/serverSocket/SystemServerSocket.class
http/server/serverSocket/WebServerSocket.class
http/server/ServerTest.class
http/templates/
http/templates/404.html
http/templates/file_directory.html
http/templates/form.html
The FileNotFoundException error you are getting is not from this line:
new File(this.getClass().getResource("/http/templates/404.html").getFile())
It appears that after you are storing these File objects in hash map, you are trying to read the file (or serve the file by reading using FileInputStream or related APIs). It would have been more useful if you had given the stack trace and the code which is actually throwing this exception.
But the point is that files present within the JAR files are not the same as files on disk. In particular, a File object represents an abstract path name on disk and all standard libraries using File object assume that it is accessible. So /a/path/like/this is a valid abstract path name, but file:/Users/Kelly/Desktop/Java_HTTP_Server/build/jar/server.jar!/http/templates/404.html is not. This is exactly what you get when you call getResource("/http/templates/404.html").getFile(). It just returns a string representing something that doesn't exist as a file on disk.
There are two ways you can serve resources from class path directly:
Directly return the stream as a response to the request. this.getClass().getResourceAsStream() will return you the InputStream object which you can then return to the caller. This will require you to store an InputStream object in your hash map instead of a file. You can have two hash maps one for files from class path and one for files on disk.
Extract all the templates (possibly on first access) to a temporary location say /tmp and then store the File object representing the newly extracted file.
I'm trying to upload an external image and I need to save it in a folder where I have a managed bean. Any idea how I could do this?
Use Class#getResource() to obtain the URL where the class is located.
URL beanClassPath = Bean.class.getResource("");
File imageFile = new File(beanClassPath.getPath(), imageFileName);
// ...
However, this is generally a very bad idea. If you redeploy the webapp, everything will get lost. Rather store the images in a fixed path somewhere outside the webapplication, e.g. /images or so. In a Windows environment this will automatically refer to the disk from where the webapplication is started, e.g. c:/images.
File imageFile = new File("/images", imageFileName);
// ...
You can also consider to store them in a database, you'll only need to store some metadata along it, such as the original filename, content type and preferably also the content length and eventually the creation and last modification timestamps. That kind of information which you would usually obtain using the java.io.File methods. You'll namely going to need them whenever you'd like to serve the image back to the webpage.