We are using velocity to parse our templates.
Velocity developer guide suggests to create a new VelocityContext for every parsing
But what about the VelocityEngine and the RuntimeInstances?
Can we reuse them or is it better to create new instances every call ? Will the new instances of VelocityEngine cause memory leaks ?
public String parse(String templateStr, Map<String, String> params) {
StringWriter writer = new StringWriter();
try {
VelocityEngine velocityEngine = new VelocityEngine();
velocityEngine.init();
RuntimeServices rs = RuntimeSingleton.getRuntimeServices();
StringReader sr = new StringReader(templateStr);
SimpleNode sn = rs.parse(sr, "template");
Template t = new Template();
t.setRuntimeServices(rs);
t.setData(sn);
t.initDocument();
VelocityContext context = new VelocityContext();
if (params != null && !params.isEmpty()) {
for (Entry<String, String> entry : params.entrySet()) {
context.put(entry.getKey(), entry.getValue());
}
}
t.merge(context, writer);
} catch (Exception e) {
LOGGER.error("Exception in velocity parsing", e);
}
return writer.toString();
}
Velocity allows you to use Singleton model
Velocity.setProperty(Velocity.RUNTIME_LOG_NAME, "mylog");
Velocity.init();
Template t = Velocity.getTemplate("foo.vm");
Developers have two options for using the Velocity engine, the singleton model and the separate instance model. The same core Velocity code is used for both approaches, which are provided to make Velocity easier to integrate into your Java application.
Basically, instead of VelocityEngine, you can use Velocity class:
This class provides a separate new-able instance of the Velocity template engine. The alternative model for use is using the Velocity class which employs the singleton model.
RuntimeInstance is an internal class you don't have to deal with.
VelocityEngine, as well as the singleton class Velocity (which relies on VelocityEngine), are re-entrant (as well as their associated template resource loaders). It means that they can safely be used in a multi-threaded environment.
Each time you instantiate a VelocityEngine, you'll need to call init() once on it. Reusing a previous VelocityEngine instance avoids the need for additional init() calls.
But the key benefit in reusing a VelocityEngine instance is to make use of automatic template parsing and caching via its resource loaders. In the code in your question, you're manually instantiating Template objects and loading them with data from strings. A cleaner way is to configure your VelocityEngine to support a "string resource loader", then store each string containing a template body within a StringResourceRepository associated with your VelocityEngine instance. This is all demonstrated for Velocity 2.1 at this StackOverflow answer.
A few notes in addition:
Velocity will take care of parsing your templates automatically with
the approach shown in the link, above. No need to manually parse or call initDocument() on a Template.
With this approach Velocity will take care of caching your templates (in parsed form)
automatically if you've configured your string resource loader (in
your VelocityEngine instance) with caching enabled.
The above two points will allow your code to be simpler and faster. You can further simplify the code: instead of calling yourVelocityEngineInstance.getTemplate() and then merge(), you can call yourVelocityEngineInstance.mergeTemplate().
When adding a template to a StringResourceRepository via a call to yourRepo.putStringResource(), you specify a template name as well as the body of the template. If there is no obvious name to use you can write an MD5 hashing function to quickly generate an MD5 hash string of the template body and use that as a unique name (got this tip from another Velocity user). If the template body ever changes that would generate a distinct name. There is a corresponding removeStringResource() method to delete templates from the string resource repository.
Once a template is placed in the string resource repository Velocity can locate it "magically" by name. You can call yourVelocityEngineInstance.resourceExists("YourTemplateName") to see if a given template exists in the repository or not.
I do not know the performance cost of instantiating and initializing a
VelocityEngine, a RuntimeInstance or a VelocityContext. Until the Velocity documentation provides clearer guidance on optimizing performance, you'll have to do your own performance testing to find out.
Related
I am working on freemarker template using Smooks for EDI Translations
I just perform the MD5 hashing of a string in 16 digit hexadecimal format..
I am not able to find the relevant syntax for implementing Md5 hashing in Freemarker logic
when trying to import
#import java.security.MessageDigest
in freemarker in smooks-config.xml file, it throws an error
Caused by: freemarker.template.TemplateNotFoundException: Template not found for name "java.security.MessageDigest"
FreeMarker templates can only #import other FreeMarker templates (see the documentation). Also, generally, you aren't supposed to calculate such things in FreeMarker templates. You should pass the already calculated hex string to the template.
But, if you can't do the above, then you can write a small utility object in Java that has the required methods, and then add that to the FreeMarker data-model, or to the FreeMarker configuration as "shared variable". However, I don't know if Smooks is configurable enough to do that.
If Smooks doesn't let you configure FreeMarker much (as needed above), you can write a TemplateMethodModel implementation in Java that calculates the value you need, and then create an instance of that inside your template as <#assign md5 = 'com.example.MyMD5Method'?new()>, and then later you can do things like ${md5(something)} in FreeMarker. (Of course, this requires that you can add a new class to your application.)
If the Md5 hashing can be performed by a static method of a given class and you really cannot do the job before the template is processed... you can expose this class to the template.
I'm not familiar with Smooks, but basically you need tell Smooks to inject a modified FreemarkerManager which has an overriden method populateContext
public class MyFreemarkerManager extends FreemarkerManager {
#Override
protected void populateContext(ScopesHashModel model, ValueStack stack, Object action, HttpServletRequest request, HttpServletResponse response) {
super.populateContext(model, stack, action, request, response);
BeansWrapper beansWrapper = new BeansWrapperBuilder(Configuration.VERSION_2_3_24).build();
TemplateHashModel staticModels = beansWrapper.getStaticModels();
TemplateHashModel utils = (TemplateHashModel)staticModels.get("path.to.your.class.Utils");
model.put("Utils", utils);
}
}
Now all your templates have a direct access to the static methods of the Utils class
${Utils.hashMd5(s)}
Freemarker is used as the default template engine in the ninja web framework. The framework assigns some default values to a template which are globaly available when using the ninja web framework. I have created an extension for the template which does enbales CSRF-Protection. The extension offers a function which can be used in a template, e.g.
${foo(bar)}
At the moment the function needs to be called with specific parameters, which is not very intuitiv. Using a macro I could simplify this call to
#{foo}
and the user doesn't need to worry about passing the correct (e.g. "bar") parameter. But to make this available in the ninja web framework I have to define a macro programmatically. Is that possible?
UPDATE
Sorry for the confusion. Meant <#foo/> instead of #{foo} ...
Looking at the Freemarker documentation I maybe can make more clear what I want to achieve: http://freemarker.org/docs/ref_directive_macro.html
Like I explained above I am passing a custom function to the template, enabling me to call
${foo("bar")}
What I want to do, is call this via a macro like
#<myMacro/>
But the defined macro like
<#macro myMacro>
${foo("bar")}
</#macro>
should not be defined in the template but programmatically. Hope that makes it more clear.
UPDATE2 / SOLUTION
I ended up using the recommended TemplateDirectiveModel.
public class TemplateEngineFreemarkerAuthenticityTokenDirective implements TemplateDirectiveModel {
private String authenticityToken;
public TemplateEngineFreemarkerAuthenticityTokenDirective(Context context) {
this.authenticityToken = context.getSession().getAuthenticityToken();
}
#Override
public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException {
if (!params.isEmpty()) {
throw new TemplateException("This directive doesn't allow parameters.", env);
}
if (loopVars.length != 0) {
throw new TemplateException("This directive doesn't allow loop variables.", env);
}
Writer out = env.getOut();
out.append(this.authenticityToken);
}
}
FreeMarker macro invocations doesn't look like #{...}. Is that some kind of Ninja-specific extension?
Anyway, if you know that there's a bar in the data-model, then your method can get it like Environment.getCurrentEnvironment().getDataModel().get("bar"), so it need not be passed in.
Also, it's maybe useful to know that FTL has two kind of "subroutines", the function-like ones, and the directive-like ones. Both can be implement both in FTL (#function, #macro) and in Java (plain Java methods, TemplateMethodModelEx, TemplateDirectiveModel). The real difference is that the function-like ones are for calculating values, and the directive-like ones are for printing values directly to the output (hence bypassing auto-escaping) and for side-effects. But all of these can reach the Environment, so there's no difference there.
You can call a macro "dynamically". Let's say you had a macro:
<#macro myMacro>
${foo("bar")}
</#macro>
You can call it like this:
<#myMacro />
OR
<#.vars["myMacro"] />
So then you can do...
<#assign someVar = "myMacro" />
<#.vars[someVar] />
I am converting the server side of my GWT project use Scala instead of Java. I have a number of RPC servlets that do DB lookups then map results to ArrayList where a class like SomeDTO might be
override def listTrips(): util.ArrayList[TripRoleDTO] = {
val trd = new TripRoleDTO
trd.setRoleType(RoleType.TripAdmin)
trd.setTripName(sessionDataProvider.get().getSessionUser.getEmail)
val res: util.ArrayList[TripRoleDTO] = new util.ArrayList[TripRoleDTO]()
res.add(trd)
res
}
instead of
#Override
public ArrayList<TripRoleDTO> listTrips() {
final SessionData sessionData = sessionDataProvider.get();
final List<TripRole> tripsForUser = tripAdminProvider.get().listTripRolesForUser(sessionData.getSessionUser().getId());
return newArrayList(transform(tripsForUser, DTOConverter.convertTripRole));
}
Note that the Java implementation actually makes the DB call (something I'm figuring out in Scala still) but it does its DTO transformation via Google Guava's Iterables.transform method.
Since the DTO objects need to be .java files that the client side of GWT can use what is an elegant way to transform my Scala domain objects to DTOS?
Use the GWT RequestFactory for automating the creation of DTOs. The DTO can be defined simply with an interface and a #ProxyFor annotation, see an example in the link provided.
If using RequestFactory by some reason is not an alternative, then consider using Dozer to map domain objects to DTOs, this is frequently used with GWT.
We're using Apache Velocity to generate HTML, and I'd like to add my own escaping to all input to our templates -- without changing our templates. Velocity seems pretty extendable, but I'm having a hard time finding my way around the framework.
Do you know if there is some easy way to escape the input without changing all my templates?
EventCartridge eventCartridge = new EventCartridge();
context.attachEventCartridge(eventCartridge);
eventCartridge.addReferenceInsertionEventHandler(new ReferenceInsertionEventHandler() {
public Object referenceInsert(String reference, Object value) {
return escaper.html(value.toString());
}
});
This can be done through a ReferenceInsertionEventHandler implementation.
According to the developer guide for Velocity 2.1: ou may
register event handlers in either of two manners. The easiest way to
register event handlers is to specify them in velocity.properties.
(Event handlers configured in this manner are referred to as "global"
event handlers). For example, the following property will escape HTML
entities in any inserted reference.
event_handler.reference_insertion.class = org.apache.velocity.app.event.implement.EscapeHtmlReference
Note that EscapeHtmlReference is deprecated. You should provide your own implementation, which can be loaded in a similar manner.
Alternatively, the handler can be loaded through code:
InternalEventContext context; // eg. VelocityContext
EventCartridge eventCartridge = new EventCartridge();
if (!eventCartridge.attachToContext(context)) {
throw new RuntimeException("Velocity context does not support event cartridge");
}
eventCartridge.addReferenceInsertionEventHandler(new ReferenceInsertionEventHandler() {
#Override
public Object referenceInsert(Context context, String reference, Object value) {
return escaper.escape(value);
}
});
In Grails, I would like to get a ConfigObject reference to the loaded messages properties file for the current locale. Or some way to easily read in the messages properties (for the current locale) in it's entirety. I want to convert it to JSON and send it back to the client to be used to lookup strings via javascript.
In essence I want to do something like this:
def props = new java.util.Properties()
props.load(... the right message bundle ...);
def messages = new ConfigSlurper().parse(props)
render messages as JSON
I'm assuming there's a more graceful way to do this. The messageSource interface only allows you to get a message for a particular key. I want the entire resource bundle so I can convert it to JSON.
I found a workable solution of just loading the properties directly from the proper messages properties bundle based on the current locale.
It looks like I can just load the file with a path relative to the root of the application. This worked for running locally both with the embedded tomcat and as a war ('grails run-app' and 'grails run-war') but I haven't tested deployed to a container to know if the path will be resolved properly.
Here's my test controller:
import grails.converters.*
import org.springframework.context.i18n.LocaleContextHolder as LCH
class I18nController {
def index = {
def locale = LCH.getLocale().toString();
def langSuffix = ( locale == "en" ) ? "" : "_${locale}"
def props = new java.util.Properties()
props.load( new FileInputStream( "grails-app/i18n/messages${langSuffix}.properties" ) )
render ( new ConfigSlurper().parse(props) ) as JSON
}
}
Can be accessed like:
http://localhost:8080/myapp/i18n
http://localhost:8080/myapp/i18n?lang=es
http://localhost:8080/myapp/i18n?lang=en
I know this is old, but I came here looking to do the exact same thing. Using LocaleContextHolder to get the desired locale is a good starting point, although I decided to use RequestContextUtils. In my implementation, I wanted to use java's own locale resolution strategy. So here goes (currently using grails 2.1.2):
// Controller
import org.springframework.web.servlet.support.RequestContextUtils
import grails.converters.JSON
class I18nController {
def strings() {
ResourceBundle clientMessages = ResourceBundle.getBundle("com.example.ClientMessages",
RequestContextUtils.getLocale(request),
Thread.currentThread().contextClassLoader)
render clientMessages as JSON
}
}
When you serialize this thing using the default JSON marshaller, it's not what you want. So add this to your BootStrap.groovy inside the init closure:
// JSON Marshaller to serialize ResourceBundle to string table.
JSON.registerObjectMarshaller(ResourceBundle) { bundle ->
def returnObject = [:]
bundle.keys.each {
returnObject."${it}" = bundle.getString(it)
}
returnObject
}
And finally, put the resources you want to send to the javascript client side in your classpath. In my example, these would go in src/java/com/example/ClientMessages.properties.
size.small=Small
size.wide=Wide
size.large=Large
In the client, going to myapp/i18n/strings you will see the JSON like this:
{"size.small":"Small","size.wide":"Wide","size.large":"Large"}
So with this solution, you put all and only the strings you want to send to the javascript side for lookup, and put everything else in the grails i18n folder. One caveat is that the strings here are not available to g:message and vice versa. If anyone can figure out a solution to single out one basename in i18n for this purpose, I'd like to see it.
The implementation type of MessageSource is org.codehaus.groovy.grails.context.support.PluginAwareResourceBundleMessageSource. Perhaps there are methods on this class (or one of it's parents), that will allow you to get a reference to the entire set of Properties.
The following looks like it might work (though I haven't tested it):
// Get a reference to the message Source either via dependency injection or looking-up
// the bean in the application context
def messageSource
Properties messages = messageSource.getProperties("messages.properties").properties
// Now convert the Properties instance to JSON using your favorite Java-JSON library
This is not a great solution as the getProperties(filename) method is protected, so you should not be able to call it, but you can because of a bug in Groovy. It also makes some implicit assumptions about the implementation type of mesageSource.