Read templates from a file StringTemplate - java

I'm using the template engine StringTemplate for some templates (obviously).
What I want is to be able to store the templates I have in seperate files, ofcourse I can do that with simple .txt files and reading them into a String, looks a bit like this then
ST template = new ST(readTemplateFromFile("template.txt"))
private String readTemplateFromFile(String templateFile){
//read template from file
}
But what I was wondering is if there's functionality in the StringTemplate engine to do that automatically. SO that i don't have to write code that already exists.
I've read something about Group Files but I don't quite understand that,are those like Template files? Or am I completely missing something?

Yes, there is functionality available that can be used directly without providing your own file loading code.
From the ST JavaDoc:
To use templates, you create one (usually via STGroup) and then inject attributes using add(java.lang.String, java.lang.Object). To render its attacks, use render().
To follow that advice the following code can be used.
First, create a file called exampleTemplate.stg and place it on your classpath.
templateExample(param) ::= <<
This is a template with the following param: (<param>)
>>
Then, render the template by using the following code:
// Load the file
final STGroup stGroup = new STGroupFile("exampleTemplate.stg");
// Pick the correct template
final ST templateExample = stGroup.getInstanceOf("templateExample");
// Pass on values to use when rendering
templateExample.add("param", "Hello World");
// Render
final String render = templateExample.render();
// Print
System.out.println(render);
The output is:
This is a template with the following param: (Hello World)
Some additional notes:
STGroupFile is a subclass of STGroup. There are other subclasses as well that you find out more about in the JavaDoc.
In the example above the template file was placed on the classpath. This is not a requirement, files can be placed in a relative folder or a in an absolute folder as well.

Related

File wildcard use *

I am trying to read a file which has name: K2ssal.timestamp.
I want to handle the time stamp part of the file name as wildcard.
How can I achieve this ?
tried * after file name but not working.
var getK2SSal: Iterator[String] = Source.fromFile("C://Users/nrakhad/Desktop/Work/Data stage migration/Input files/K2Ssal.*").getLines()
You can use Files.newDirectoryStream with directory + glob:
import java.nio.file.{Paths, Files}
val yourFile = Files.newDirectoryStream(
Paths.get("/path/to/the/directory"), // where is the file?
"K2Ssal.*" // glob of the file name
).iterator.next // get first match
Misconception on your end: unless the library call is specifically implemented to do so, using a wildcard simply doesn't work like you expect it to.
Meaning: a file system doesn't know about wildcards. It only knows about existing files and folders. The fact that you can put * on certain commands, and that the wildcard is replaced with file names is a property of the tool(s) you are using. And most often, programming APIs that allow you to query the file system do not include that special wild card handling.
In other words: there is no sense in adding that asterisk like that.
You have to step back and write code that actively searches for files itself. Here are some examples for scala.
You can read the directory and filter on files based upon the string.
val l = new File("""C://Users/nrakhad/Desktop/Work/Data stage migration/Input files/""").listFiles
val s = l.filter(_.toString.contains("K2Ssal."))

providing automization with Xtext and Java program

In my current project, I am using xText editor for writing my dsl specifications (i.e., voc.mydsl, arch.mydsl, and network.mydsl). I like the xText editor because of its code-completion and other functionalities.
However, I have a separate Java program. This java program takes text files (i.e., voc.txt, arch.txt, network.txt) as inputs, parse these files using ANTLR parser, and generates code using StringTemplate files.
Now, my problem is that currently, I have to follow these steps manually:
(1) I write dsl specifications in XText editor (voc.mydsl, arch.mydsl, and network.mydsl).
(2) I copy-paste these specification into three text files (i.e., voc.txt, arch.txt, network.txt).
(3) Finally, I run the Java program to parse these .txt files and generate code.
Is there any way that I can automize (performed in a single click) all the above three steps? Let me know if you need any detail.
You could write a "special" generator for your DSL. XText will call this generator whenever you edit and save a *.mydsl file. What you actually do in this "Generator" thing is of no interest to Xtext. So your MydslGenerator.xtend generator could look like this:
// whereever Xtext generates your empty version of this file
package mydsl.xtext.generator
// add imports
#Singleton
class MydslGenerator implements IGenerator {
override void doGenerate(Resource resource, IFileSystemAccess fsa) {
// calculate new filename
val newFilename= resource.URI.lastSegment.replaceAll(".mydsl", ".txt")
// get text representation of parsed model
val textContent = resource.contents.map[NodeModelUtils::getNode(it).text].join
// write text content to new file
fsa.generateFile(newFilename, textContent);
// TODO: call ANTLR parser on new file here
}
}
In the last step you can call your "other" program either by calling its main method directly from Eclipse or by invoking a new JVM. The later is only advisable if the other generator works quickly because it is called whenever you save a *.mydsl file. The first method is only advisable when the other program has no memory leaks and has not to many jar dependencies.

How can I inject an XML file using Selenium?

I have the path to my XML file on my computer, but how can I use selenium (web automation tool) to inject the XML file ?
Usually how it is done (manually) is navigate to the URL and COPY AND PASTE the entire XML text into the provided text box..
Any ideas how to inject the file using automation ? There is no way to "drag" the XML file to the text box and I believe the way I'm thinking that it will work is very complicated.
I think this is actually what you want -
File xml = new File("xmlpath");
String url = xml.getAbsolutePath();
url = url.replace('\\', '/');
url = url.replace(" ", "%20");
String actual = "file:/" + url;
selenium.open(actual);
Then you should be able to get the xml using String theXML = selenium.getText("//rootxmlnode"); Then do what you will with it.
Check out the topic of Data Driven Testing to get you started. Something like this should get you going.
Selenium tool allows you to create an automatically generated code in Java.
So, you need to place any text in the provided text box and generate this Java-test code.
Next step is modifying of the generated test. You have to manually write a simplest code, which will read your XML file, get it contents and paste into the text box. The last thing is replacement (in the generated Java code of test!) of the mentioned above text-block to the contents of read XML.
A simplest way for reading file into a string is using Apache commons-io library.
For example: FileUtils.readFileToString(File file, String encoding) gives you a string object with contents of the file.

Importing freemarker macros

My macros.txt file is
<#macro macro1>
Helloworld.
</#macro>
I have another file testMacro.txt. I want to use this macro inside the file testMacro.txt.
I have tried the following
<#import "./macros.txt" as my>
<#my.macro1 />
But it does not seem to be working.
In my java file, where I am working with the template file, I have(in my MacroWorking.java)
template = new Template(null,new FileReader("testMacro.txt"),new configuration());
Exception are.
Exception in thread "main" java.lang.NullPointerException
at freemarker.core.LibraryLoad.<init>(LibraryLoad.java:82)
at freemarker.core.FMParser.Import(FMParser.java:1727)
at freemarker.core.FMParser.FreemarkerDirective(FMParser.java:2389)
at freemarker.core.FMParser.Content(FMParser.java:2618)
at freemarker.core.FMParser.OptionalBlock(FMParser.java:2786)
at freemarker.core.FMParser.Root(FMParser.java:2958)
at freemarker.template.Template.<init>(Template.java:149)
at freemarker.template.Template.<init>(Template.java:172)
at msjava.hdom.examples.DbQuery.main(MacroWorking.java:24)
Line 24 of MacroWorking.java is the one given above.
EDIT: With the same code but with my testMacro.txt having text as HELLOWORLD only, i.e. no import statement, then it works fine.
What do I do?
Thanks.
There's no problem with those templates, the problem is with the way you are using the Java API of FreeMarker.
When #import tries to resolve the ./macros.txt path, it tries to resolve it relatively to the path of the current template, but since the template was loaded from a Reader and you have passed null as template name (that's the same as the template path), it will run into an NPE situation. That's an improper error message, but it couldn't resolve that path anyway, as it has no idea where the current template came from (remember, you have only given a Reader to FreeMarker). The proper way is:
Configuration cfg = new Configuration();
cfg.setDirectoryForTemplateLoading(new File("/where/you/store/the/templates"));
Template template = cfg.getTemplate("testMacro.txt");
Now FreeMarker sets the name of the template to testMacro.txt and it also takes care of loading and caching of it. If you still need to load templates directly from a Reader, you can do it as:
Template template = new Template("testMacro.txt", new FileReader(...), cfg);
Note the non-null template name. It doesn't mater if that's real, but it will be used to resolve relative paths in that template. Also note that the template-loader must be set correctly in the Configuration, because FreeMarker works with virtual-paths.

Velocity, different template paths

Does anyone know if it is possible to get templates from different paths with velocity? After initialization Velocity refuses to change the "file.resource.loader.path".
This is my code:
public Generator(){
Properties p = new Properties();
p.setProperty("resource.loader", "file");
p.setProperty("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
p.setProperty("file.resource.loader.path", "");
Velocity.init(p);
}
The templates can be located in different locations ( the user can select one with a file dialog ). So I have this code upon fetching the template out of velocity
private Template fetch (String templatePath) {
out_println("Initializing Velocity core...");
int end = templatePath.lastIndexOf(File.separator);
Properties p = new Properties();
p.setProperty("file.resource.loader.path", templatePath.substring(0, end));
Velocity.init(p);
return Velocity.getTemplate(templatePath.substring(end+1));
}
This is not working. It seems that once Velocity is initialized it can't be reset with different properties. Any suggestions on how to solve this problem?
Possible Program flow:
User selects group that needs to be filled into the template
User selects a template to use (can be located anywhere on the hdd)
User presses generate
Velocity can be used in two ways: the singleton model or the separate instance model. You are currently using the singleton model in which only one instance of the Velocity engine in the JVM is allowed.
Instead, you should use the separate instance model which allows you to create multiple instances of Velocity in the same JVM in order to support different template directories.
VelocityEngine ve = new VelocityEngine();
ve.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, "path/to/templates");
ve.init();
Template t = ve.getTemplate("foo.vm");
Adding to the points above:
Even if one is using non-singleton model i.e using VelocityEngine object. Multiple paths can be configured by giving comma separated values to the property.
[file.resource.loader.class=path1,path2]
In such a case velocity engine will look for template in path1 first and then in path2
Consider instead of using singleton Velocity class creating and initializing new VelocityEngine before step 3.
In my case I am using Velocity with Servlets in an Eclipse Dynamic Web Project.
I couldn't actually reset the path, but I could put a subdirectory under /WebContent folder and then organize my templates that way... and have nested subdirectories as well.
RequestDispatcher requestDispatcher =
request.getRequestDispatcher("/velocity_templates/index.vm");
This simple solution was all I needed ... didn't need to mess with velocity.properties in web.xml or setting them programmatically (in each case, neither approach worked for me unfortunately when I tried).
Note that when I do template includes with #parse(..) command, I need to use the same path prefix inside the template .vm file as I did in the example code for my servlet.

Categories