I'm working on a task that's using Velocity to generate an email from a template. One of my requirements is that the email message be localized, based on a Locale submitted by the user. I've got this working for the most part, using Velocity's ResourceTool to pull in a MessageBundle. The other requirement is that I can only have one template - I don't want one template per language or locale because this is difficult to maintain if changes are needed.
As a part of a MessageBundle, I can have what's referred to as "compound messages", which are messages that have variables that are replaced when the message is evaluated. For example:
dear.name=Dear {0}:
My question is this: how do I get Velocity to replace the {0} value with a name that I pass in?
It's not acceptable to simply modify my Velocity template so that I simply replace the name at the template level - in some languages, the greeting word "Dear" comes after the name, so this would yield an incorrect output.
Found the answer: in my velocity template, I can use the Velocity directive:
#evaluate(${msg.dear.name})
And in my message bundle, my message looks like:
dear.name=Dear $name
If I set the name in the Velocity context, it gets replaced as I expect.
Related
In my web application I'm trying to prevent users from inserting JavaScript in the freeText parameter when they're running a search.
To do this, I've written code in the header Velocity file to check whether the query string contains a parameter called freeText, and if so, use the replace method to replace the characters within the parameter value. However, when you load the page, it still displays the original query string - I'm unsure on how to replace the original query string with my new one which has the replaced characters.
This is my code:
#set($freeTextParameter = "$request.getParameter('freeText')")
freeTextParameter: $freeTextParameter
#if($freeTextParameter)
##Do the replacement:
#set($replacedQueryString = "$freeTextParameter.replace('confirm','replaced')")
replacedQueryString after doing the replace: $replacedQueryString
The query string now: $request.getQueryString()
The freeText parameter now: $request.getParameter('freeText')
#end
In the code above, the replacedQueryString variable has changed as expected (ie the replacement has been carried out as expected), but the $request.getQueryString() and $request.getParameter('freeText') are still the same as before, as if the replacement had never happened.
Seeing as there is a request.getParameter method which works fine for getting the parameters, I assumed there would be a request.setParameter method to do the same thing in reverse, but there isn't.
The Java String is an immutable object, which means that the replace() method will return an altered string, without changing the original one.
Since the parameters map given by the HttpServletRequest object cannot be modified, this approach doesn't work well if your templates rely on $request.getParameter('freeText').
Instead, if you rely on VelocityTools, then you can rather rely on $params.freeText in your templates. Then, you can tune your WEB-INF/tools.xml file to make this parameters map alterable:
<?xml version="1.0">
<tools>
<toolbox scope="request">
<tool key="params" readOnly="false"/>
...
</toolbox>
...
</tools>
(Version 2.0+ of the tools is required).
Then, in your header, you can do:
#set($params.freeText = params.freeText.replace('confirm','replaced'))
I managed to fix the issue myself - it turned out that there was another file (which gets called on every page) in which the $!request.getParameter('freeText')" variable is used. I have updated that file so that it uses the new $!replacedQueryString variable (ie the one with the JavaScript stripped out) instead of the existing "$!request.getParameter('freeText')" variable. This now prevents the JavaScript from being executed on every page.
So, this is the final working code in the header Velocity file:
#set($freeTextParameter = "$!m.request.httpRequest.getParameter('freeText')")
#if($freeTextParameter)
#set($replacedQueryString = "$freeTextParameter.replace('confirm','').replace('<','').replace('>','').replace('(','').replace(')','').replace(';','').replace('/','').replace('\"','').replace('&','').replace('+','').replace('script','').replace('prompt','').replace('*','').replace('.','')")
#end
I'm working on an application, where the SIPSession generated by Mobicents has one of it's attribute coming as null. After digging through the source code, I found out that, the value returned from the SipSession#getId() method is nothing but the SessionKey.
The SessionKey internally uses 4 different parameters to generate the String representation of the key. Out of that, one of the attribute is: fromTag. You can look at the source code of SipSessionKey here. Now, I'm unable to understand, what exactly is that fromTag. When I saw the request which is being sent, there is definitely a vlaue in the From header of the SipRequest. The From header is in the form:
From: <tel:+xxxxxxxxx>
That's it. What is fromTag in there? Why I'm getting it as null?
According to section 8.1.1.3 of RFC 3261, the From header MUST have a tag parameter. This is one of the pieces of data used to identify the dialog. (The others are Call-ID and the tag on the To header, generated by the UAS.) One the examples shown in the RFC is:
From: sip:+12125551212#phone2net.com;tag=887s
When looking at the SIP message received by the Mobicents container, is there a tag parameter on the From header?
Was wondering why the constraints created for a form are not included in the input tag directly when created through the form helper?
Explanation (using Play 2.1):
Model:
public class Account {
#MaxLength(5)
private String id = "";
...
...
view:
#form(action = routes.Application.addAccount()) {
#inputText(accountForm("id"), '_label -> "Enter your id:")
}
renders automatically in html as:
Enter your id:
Maximum length: 5
Should it not render like this (actually constraining the form text field):
Enter your id:
Maximum length: 5
How can I get code that will automatically include constraints such as these in the form? It's just that I do not really think it is a good idea to have a maxlength defined in the form model and a separate one defined in the view.
Thanks
If I've understood you correctly, it sounds like you're looking to implement one of these features:
Highlight an input text field that is overlength before form submission
Clipping text in an input field so that it does not go overlength
Play's HTML templating engine doesn't natively provide this kind of client-side instant form validation. This functionality needs to be implemented via JavaScript, and JavaScript generation is not really a concern for Play.
If you want to progressively enhance your form and provide client-side validation, you'll have to write the JavaScript yourself. Of course there are libraries that you can use to help you with this task. For example, if you are already using jQuery you can use its validation plugin.
As you've mentioned in your question, it would be better to have a maximum length limit declared in one place only, rather than duplicated in your client-side JavaScript code and your server-side Java code. As a suggestion, you could keep the limit declared in Java code, but introduce a new action in your controller tier that returns a JSON response containing this limit. This action could then be called via AJAX when loading your form page.
EDIT
Didn't know about the maxlength attribute, thanks Saad. If you feed in your maximum length limit as an input parameter to your template, you can populate an input element's maxlength attribute as follows:
#(accountForm: Form[Account], maxLength: Int)
...
#form(action = routes.Application.addAccount()) {
...
#inputText(
field = accountForm("id"),
args = '_label -> "Enter your id:", 'maxlength -> maxLength
)
...
}
...
There may be a more elegant way to pass maxLength into your HTML template (e.g use the HTTP context map, or have it as a public field on your Account form object). The above code snippet just demonstrates how to correctly generate the input text field once you can access it in the template.
I'm using Apache Velocity in an internationalized Spring MVC website.
I want to use "Redirecting in X seconds" as the phrase (message key) that my translators will translate. The X will obviously be a variable number of seconds, and Javascript will update the page every second to count it down.
I thought I'd do this:
#springMessageText("Redirecting in {0} seconds" ["<span class='seconds'>5</span>"])
But this displays:
Redirecting in <span class='seconds'>5</span> seconds
(without parsing the HTML).
I need to be able to put the HTML tag in there because that is how javascript will know which part of the translated phrase to update.
What am I doing wrong?
UPDATED ANSWER:
I created a custom macro file called custom.vm:
#macro( springMessageHtml $code, $args, $defaultValue)
$springMacroRequestContext.getMessage($code, $args.toArray(), $defaultValue, false)
#end
In my velocity.properties file, I changed this line to reference it:
velocimacro.library=org/springframework/web/servlet/view/velocity/spring.vm,/velocity/custom.vm
And now in my views (like sample.vm), I can call it like:
#springMessageHtml("Redirecting in {0} seconds" ["<span class='seconds'>5</span>"])
OLDER ANSWER:
I found an answer here: http://feima2011.wordpress.com/2011/01/18/misc-notes/
#set($args = ["<span class='seconds'>5</span>"])
$springMacroRequestContext.getMessage("Redirecting in {0} seconds",
$args.toArray(), "", false)
#springMessageText is just a macro that calls $springMacroRequestContext.getMessage() anyway; by calling it directly, I'm able to specify that last parameter (a boolean for whether to escape the HTML).
Now I'm able to have unescaped HTML. Maybe eventually I'll code a new macro called #springMessageHtml, and it will call $springMacroRequestContext.getMessage() with the escapeHtml parameter set to False. Then in my view, I'd only need 1 line of code.
Consider a string template of the following format:
String template = "The credentials you provided were username '{0}' with password '{1}'";
Substitution variable fields are of the form {n}, where n is a zero based index.
This is the template format used in Adobe Flex, see StringUtil.substitute(...). And also .NET, IIRC.
Since I want to re-use the templates used by the Flex code I'm looking for an Java equivalent. I'm aware of String.format(...) but the template structure is not identical.
What is the best way to get the same "Flex compatible" template functionality in Java?
Basically this is the desired end-result:
assert(StringUtil.substitute(template, "powerUser", "difficultPassword") == "The credentials you provided were username 'powerUser' with password 'difficultPassword'");
Use MessageFormat
You want java.text.MessageFormat http://download-llnw.oracle.com/javase/6/docs/api/java/text/MessageFormat.html