Calling TagLib stuff in Grails console? - grails

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

Related

Grails, how to get the request object

Grails has a request object which is defined here.
The problem is when I try to use it, I get:
No such property: request for class:xxx
Reading the first 100 hits googling this error only produced one suggestion:
import javax.servlet.http.HttpServletRequest
import org.springframework.web.context.request.ServletRequestAttributes
:
def my() {
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest();
}
However, this gives:
groovy.lang.MissingPropertyException: No such property: RequestContextHolder for class: net.ohds.ReportService
How does one get a handle on the request object in Grails?
How do you find out about this? So few people have asked this question, it must be documented somewhere, or in some example, but I can't find either.
In Grails 3.0, from a service get the request object using:
grails-app/services/com/example/MyService.groovy
import org.grails.web.util.WebUtils
...
def request = WebUtils.retrieveGrailsWebRequest().getCurrentRequest()
def ip = request.getRemoteAddr()
Documentation:
https://docs.grails.org/latest/api/org/grails/web/util/WebUtils.html#retrieveGrailsWebRequest()
Note:
The old codehaus package has been deprecated.
Try following code:
import org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequest
import org.codehaus.groovy.grails.web.util.WebUtils
...
GrailsWebRequest webUtils = WebUtils.retrieveGrailsWebRequest()
def request = webUtils.getCurrentRequest()
I expect that you probably got "groovy.lang.MissingPropertyException: No such property: RequestContextHolder for class: net.ohds.ReportService" because you didn't import the "org.springframework.web.context.request.RequestContextHolder" class in your ReportService.
The most common place to want access to the request object is in a controller. From a controller you simply refer to the request property and it will be there. See http://grails.org/doc/latest/ref/Controllers/request.html.
The answer to how to access the request object from somewhere else may depend on what the somewhere else is.
UPDATE
I don't know why you are having trouble passing the request from a controller to a service, but you can. I suspect you are invoking the method incorrectly, but something like this will work...
// grails-app/services/com/demo/HelperService.groovy
package com.demo
class HelperService {
// you don't have to statically type the
// argument here... but you can
def doSomethingWithRequest(javax.servlet.http.HttpServletRequest req) {
// do whatever you want to do with req here...
}
}
A controller...
// grails-app/controllers/com/demo/DemoController.groovy
package com.demo
class DemoController {
def helperService
def index() {
helperService.doSomethingWithRequest request
render 'Success'
}
}

How to use g.formatNumber in grails Service class

I want to use g.formatNumber in service, I have tried a below method, Which i got online. This is not working, its giving me the error "Cannot invoke method formatNumber() on null object", The code is below
import org.springframework.beans.factory.InitializingBean
class MyService implements InitializingBean {
boolean transactional = false
def gspTagLibraryLookup // being automatically injected by spring
def g
public void afterPropertiesSet() {
g = gspTagLibraryLookup.lookupNamespaceDispatcher("g")
assert g
}
def getFormattedNumber(){
def number = g.formatNumber(number: 5000,234 , type: "number" , maxFractionDigits: 2)
return number
}
}
How to do this.
I want to use g.formatNumber in service
Rather than jumping through the hoops you need to use a taglib within a service, it would be simpler to just use java.text.NumberFormat directly
NumberFormat format = NumberFormat.getNumberInstance()
format.maximumFractionDigits = 2
def number = format.format(5000.234)
If the service method is being called from a web request handling thread then you may wish to use the LocaleContextHolder to get the correct locale for the current web request, rather than just using the server's default.
This should work
def g = grailsApplication.mainContext.getBean('org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib');
You will of course need grailsApplication injected by defining it ala
def grailsApplication

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>

Groovy script to Grails app

Well I am new to Groovy/Grails. I have written a Groovy script that uses RESTClient to make HTTP POST request to JIRA server. The POST request sends a JQL query and receives the result in JSON format. Here's the full code:
import groovyx.net.http.RESTClient;
import groovyx.net.http.HttpResponseDecorator;
import org.apache.http.HttpRequest;
import org.apache.http.protocol.HttpContext;
import org.apache.http.HttpRequestInterceptor;
import groovy.json.JsonSlurper;
import static groovyx.net.http.Method.*
import static groovyx.net.http.ContentType.*
#Grab(value = 'org.codehaus.groovy:groovy-all:2.1.6',
initClass = false)
#Grapes([
#Grab(group = 'org.codehaus.groovy.modules.http-builder',
module = 'http-builder', version = '0.5.2'),
#GrabExclude('org.codehaus.groovy:groovy')
])
// connect to JIRA
def jiraApiUrl = 'http://my-jira.com/rest/api/2/'
def jiraClient = new RESTClient(jiraApiUrl);
// authentication
def basic = 'Basic ' + 'username:password'.bytes.encodeBase64().toString()
jiraClient.client.addRequestInterceptor (
new HttpRequestInterceptor() {
void process(HttpRequest httpRequest,
HttpContext httpContext) {
httpRequest.addHeader('Authorization', basic)
}
})
// http post method
def uriPath = 'search'
def param = [maxResults : 1, jql : '<jql-query>']
def Issues = jiraClient.post(requestContentType : JSON, path : uriPath, body : param)
def slurpedIssues = new JsonSlurper().parseText(Issues.data.toString())
println Issues.data.total
I need to migrate this script to a Grails app. Any suggestions as to how to do the same?
Define dependencies in BuildConfig (except the groovy dependency)
copy script contents to a Service
Possible extension:
use the grails rest plugin or grails rest-client-builder plugin instead of http-builder
Putting the logic into Service object will give you the ability to do dependency injection, which is native to grails services.
Also, you should consider using AsyncHTTPBuilder if your app has many users trying to make requests.
I strongly believe that the service response will be directly rendered to JSON
//your controller
class AbcController{
//your action
def save() {
render(abcService.save(params) as JSON)//your service response now been rendered to JSON
}
}
//your service class class AbcService {
def save(params){
....
return something
}
}

Fetching some value from message.properties in 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.

Resources