Fetching some value from message.properties in Grails - grails

Want to fetch a value from message.properties file in grails in a job , how can I do that ??
My Job:
def execute() {
// execute task
List<String> emails = NayaxUser.findAllByEmailSent(false)*.username
emails.each {emailAddress->
mailService.sendMail {
//todo: FETCH FROM MESSAGE.PROPERTIES
to emailAddress
from FETCH FROM MESSAGE.PROPERTIES
subject FETCH FROM MESSAGE.PROPERTIES
html body.toString()
}
}
}

You can use:
g.message(code: 'my.message.code')
//or
g.message(code: 'my.message.code', args: [arg1, arg2])

You can inject the messageSource to retrieve the message:
class MyJob {
def messageSource
def execute() {
...
def message = messageSource.getMessage('message.code', ...)
...
}
}
Here's the documentation for getMessage(); you need to provide a couple more method arguments, namely args (an Object[]) and a Locale.

You can get a reference to the messageSource bean from anywhere using:
import org.codehaus.groovy.grails.commons.ApplicationHolder
import org.springframework.context.MessageSource
MessageSource messageSource = ApplicationHolder.application.mainContext.getBean('messageSource')
You can then get the messages themselves using the methods of the MessageSource interface.

Just as an addition to above answers, there could be following places where you need to implement internationalisation or fetch the message from message bundles.
views
controllers
services
Filters
Utility files(e.g. in util package or generalised exception message handling)
Special files e.g. in Shiro security rest realms
Below are the elaborate usage scenarios:
Views:- we have taglib available with message tag. Use this on views.
controllers :- message method is by default available here and locale conversion is automatically handled. See enter link description here
service: we may call taglibs inside services as below:
def myCustomTaglib = grailsApplication.mainContext.getBean('com.custom.MyCustomTagLib');
Or inject messageSource bean as
def messageSource
4.Filters / utility / Special files:- For these you may create something like below and then use it throughout.
String i18nMessage(def input,String defaultMessage) {
String[] languageCode = RequestContextHolder.currentRequestAttributes().request.getHeader("Accept-Language").split("-")
Locale locale = languageCode.length == 2 ? new Locale(languageCode[0], languageCode[1]) : new Locale(languageCode[0])
String message = defaultMessage
try {
message = messageSource.getMessage(input.code,input?.args?.toArray(),locale)
}catch (NoSuchMessageException nsme ){
log.info("No such error message--> ${nsme.getMessage()}")
}
return message
}
Also, if you get exception below:
java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
Then, you might need to add request listener to your web.xml
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
Note: web.xml is not available by default, you need to generate it from template.
These are the most common places you might need message bundle conversions.
Solution at point 4 would work in almost all cases. If you notice locale has been handled here manually which we could pass after fetching from requestHeader or request params optionally.
Hope it helps.

Related

Grails 2.5.5 - How to improve the internationalization of error messages in service layer?

I'm developing a web application where my business logic requires several types of error messages.
Due to this in my services layer I have several calls to the messageSource.
def messageSource
At the same time, my application must support several languages ​​so I need to define the Locale as specified by the user.
To do this, I'm getting the Locale as follows:
def request = RequestContextHolder.currentRequestAttributes().request
Locale myLocale = RequestContextUtils.getLocale(request)
But I note that this code is repeated throughout my service layer. ie:
def myMethod(){
...
messageSource.getMessage("message.code", [args] as Object[],"Default message",getLocale())
...
}
Locale getLocale(){
def request = RequestContextHolder.currentRequestAttributes().request
return RequestContextUtils.getLocale(request)
}
Is there any elegant way to share this method among all my services and controllers? Or is there any other way to improve this behavior?
Grails 2.5.5 - Groovy 2.4.4
Thanks!
You can implement the methods in a Groovy trait, and then use the trait in your services.
src/groovy/com/foo/bar/SessionLocale
trait SessionLocale {
def getMessage(String code, String defaultMessage, Object [] args) {
messageSource.getMessage(code, args, defaultMessage,getLocale())
}
Locale getLocale(){
def request = RequestContextHolder.currentRequestAttributes().request
return RequestContextUtils.getLocale(request)
}
}
grails-app/services/com/foo/bar/SomeService
class SomeService implements SessionLocale {
def myMethod(){
...
getMessage("message.code", "Default message", [args] as Object[])
...
}
}

how to use session inside groovy thread

I am new to Groovy. I want to update session variables inside a Groovy thread.
I can't put real code so I am putting sample code.
public updatename()
{
println(session["firstname"]);
Thread.start
{
session["firstname"] = "atul";
println(session["firstname"]);
}
}
I am able to access session variable outside of thread, but I am getting the following error for session inside thread
"Error java.lang.IllegalStateException: No thread-bound request found:
Are you referring to request attributes outside of an actual web
request, or processing a request outside of the originally receiving
thread? If you are actually operating within a web request and still
receive this message, your code is probably running outside of
DispatcherServlet/DispatcherPortlet: In this case, use
RequestContextListener or RequestContextFilter to expose the current
request."
Any idea how can i use session variable inside thread
Generally you can only access the session from within the scope of a web request handling thread, because you need the request context to know which session to use. A reference to the session property in a Grails controller is actually a Groovy-style call to a getSession() method injected into the class by Grails that dynamically fetches the correct session from the current request.
It may be possible to store a reference to this session in a local variable in the controller action, and then refer to that variable within the Thread.start closure:
public updatename()
{
println(session["firstname"]);
def theSession = session
Thread.start
{
theSession["firstname"] = "atul";
println(theSession["firstname"]);
}
}
but I haven't tried this myself.
Try adding following in web.xml
<web-app ...>
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
</web-app>
And it not works, you can make a simple DTO (POJO) and pass that to thread.

MultiLingual Email template with grails

I am trying to send emails from grails and the mail template should be multilingual.
I found that we can render GSP as a string or even in the grails mail plugin we can render the GSP.
In the GSP now I read the static messages from messages.properties assuming that I would define for each languages and my emails would go multi lingual.
Now here is the problem that I am facing
In the template the language is always set to en_US. I am using the below API to get the string of the template. I am not using mail plugin directly as I need to store the send message as string into the database as well
def contents = groovyPageRenderer.render(template:"/layouts/emailparse", model:[mailObj: mailObj])
I also read on other post on forum about setting the language using lang parameter but still the language is set to en_US only.
Would the above method call support specifying language?
Is there an option to use velocity template to do this kind of multilingual mails?
If you're sending the mail from within a request handling thread (e.g. from a controller action) then it should pick up the right locale from the request automatically. If you're sending from a background thread then it won't know what locale to use because there's no "current request" context.
If you have another way to know the correct language to use (e.g. if you store each user's preferred language in the database) then you could reset the LocaleContextHolder
def savedContext = LocaleContextHolder.getLocaleContext()
LocaleContextHolder.setLocale(correctLocaleForThisUser)
try {
def contents = groovyPageRenderer.render(template:"/layouts/emailparse", model:[mailObj: mailObj])
// etc. etc.
} finally {
LocaleContextHolder.setLocaleContext(savedContext)
}
Exactly how you determine the correctLocaleForThisUser depends on your application. You could store each user's preferred language as a property of the User domain object in the database, or if you're using something like the executor plugin's runAsync from a controller action then you could save the request locale while you have access to it and then re-use that in the async task:
// SomeController.groovy
def sendEmail() {
// get locale from the thread-local request and save it in a local variable
// that the runAsync closure can see
Locale localeFromRequest = LocaleContextHolder.getLocale()
runAsync {
def savedContext = LocaleContextHolder.getLocaleContext()
// inject the locale extracted from the request
LocaleContextHolder.setLocale(localeFromRequest)
try {
def contents = groovyPageRenderer.render(template:"/layouts/emailparse", model:[mailObj: mailObj])
// etc. etc.
} finally {
LocaleContextHolder.setLocaleContext(savedContext)
}
}
}
Can you work around this by creating a model containing a list with the correct translations?
For example:
def messages = [:]
messages['hello.world'] = messageSource.getMessage(
"hello.world",
null,
new Locale("nb")
)
def template = groovyPageRenderer.render(
template: '/mail/email',
model:[messages:messages]
)
And then in the view you just write:
<html>
<head>
<title>${messages['hello.world']}</title>
</head>
<body>
</body>
</html>

NullPointerException with dependency injection

I am trying to use dependency injection for export to excel functionality provided by "Export Plugin"
It seems that whenevery I try to use service in my project i get error like following
Stacktrace follows:
java.lang.NullPointerException: Cannot invoke method export() on null object
at pm.ProjectsController$_closure2.doCall(ProjectsController.groovy:39)
at pm.ProjectsController$_closure2.doCall(ProjectsController.groovy)
at java.lang.Thread.run(Thread.java:662)
The code I am using is following, this just means service variable is null
def exportService// i have tried with and without the initialization
if(params?.format && params.format != "html"){
response.contentType = ConfigurationHolder.config.grails.mime.types[params.format]
response.setHeader("Content-disposition", "attachment; filename=books.${params.extension}")
exportService.export(params.format, response.outputStream,projectsList, [:], [:])
}
It seems that no plugin that uses services is working in my project for example AsynchronousMailService in my project didn't work as it was suppose to and thus I have been using it like following
AsynchronousMailService asynchronousMailService = new AsynchronousMailService()
asynchronousMailService.sendAsynchronousMail {
to projectsInstance.projectLead.emailAddress
subject "New project is assigned to you"
html msg
}
Unless I am missing somethig very basic I do not beleive I should be instantiating this class if the plugin offers the same as service.
Thanks
Right, you should never instantiate services or other Spring beans - use dependency injection. It might work, but if the bean has any dependencies of its own they'll be null since you're bypassing Spring.
You're not using dependency injection, you're declaring a local variable and expecting magic.
Dependency injection in Grails uses public fields. Since Groovy creates a public field into a getter and setter under the hood, Spring sees the setter and Grails is configured to inject by name, so as long as the field/setter matches a Spring bean name it works.
So your controller should look something like this:
class MyController {
def exportService
def myAction = {
if (params?.format && params.format != "html") {
response.contentType = grailsApplication.config.grails.mime.types[params.format]
response.setHeader("Content-disposition",
"attachment; filename=books.${params.extension}")
exportService.export(params.format,
response.outputStream,projectsList, [:], [:])
}
}
}
Note that I also removed the use of ConfigurationHolder since it's deprecated. The best way to get access to the config is from the grailsApplication bean. It's already injected in controllers (and taglibs), and in a service or other bean you'd just need a def grailsApplication field declaration.

Calling TagLib stuff in Grails console?

Is there a way to call a taglib closure from inside the grails console? I want to be able to get at the message tag within the grails console and I can not figure this out...
You can get the configured taglib, but most expect to be running in the context of a web request. To get around that you can bind a mock request:
import grails.util.GrailsWebUtil
GrailsWebUtil.bindMockWebRequest ctx
def g = ctx.getBean('org.codehaus.groovy.grails.plugins.web.taglib.ValidationTagLib')
String message = g.message(code: 'default.button.delete.confirm.message')
You can also get messages for other languages by setting the locale of the request, e.g.
import grails.util.GrailsWebUtil
def webRequest = GrailsWebUtil.bindMockWebRequest(ctx)
webRequest.currentRequest.addPreferredLocale(Locale.GERMANY)
def g = ctx.getBean('org.codehaus.groovy.grails.plugins.web.taglib.ValidationTagLib')
String message = g.message(code: 'default.button.delete.confirm.message')
Using #Burt console plugin this is even easier as we don't have to mock the web request...
import org.codehaus.groovy.grails.plugins.web.taglib.ValidationTagLib
// Getting the class name to reduce horizontal
// scrolling in StackOverflow
def g = ctx.getBean(ValidationTagLib.class.getName())
g.message(code: 'default.button.delete.confirm.message');
You can get a list of all the tagLibs in your application by running this code in the console...
// prints a bean name per line.
ctx.getBeanNamesForType(Object).findAll {
it =~ /.*TagLib$/
} .sort() {println it}
// add false to prevent console printing the map out
false

Resources