Grails UrlMappings with parameter values containing "." - grails

Given this UrlMapping:
"/foo/$foobar" {
controller = "foo"
action = "foo"
constraints {
}
}
Combined with this controller:
class FooController {
def foo = {
def foobar = params.foobar
println "foobar=" + foobar
}
}
And with these requests:
http://localhost:8080/app/foo/example.com give the output "foobar=example"
http://localhost:8080/app/foo/examplecom give the output "foobar=examplecom"
It seems like Grails cuts the "foobar" parameter at the first dot ("."). Is this intentional? Is there a work-around if I want to use parameters containing dots in my URL mappings?

This can be solved by setting ...
grails.mime.file.extensions = false
... in Config.groovy.
It seems like Grails is trying to do some MIME magic behind the scene based on the file name suffix.
Updated: Some additional info from the Grails JIRA.
This is the offending code in UrlMappingsFilter.java:
if(WebUtils.areFileExtensionsEnabled()) {
String format = WebUtils.getFormatFromURI(uri);
if(format!=null) {
MimeType[] configuredMimes = MimeType.getConfiguredMimeTypes();
// only remove the file extension if its one of the configured mimes in Config.groovy
for (MimeType configuredMime : configuredMimes) {
if (configuredMime.getExtension().equals(format)) {
request.setAttribute(GrailsApplicationAttributes.CONTENT_FORMAT, format);
uri = uri.substring(0, (uri.length() - format.length() - 1));
break;
}
}
}
}
WebUtils.areFileExtensionsEnabled() returns the value of the "grails.mime.file.extensions" setting configured in Config.groovy.

Related

Grails filter to catch defaultAction, when the default action is not index

In a controller I have ...
class TestController {
static defaultAction = "custom"
// ...
def custom() {
// ...
So when I hit the app on http://localhost:8080/test
It defaults to the custom method
I've set up a filter with
class TestDriveControlFilters {
def filters = {
contextControl(controller:'test', action:'custom') {
before = {
But this is only hit on /test/custom
not on /test or /test/
How do I set up the filter in a nice way to catch both.
After some trial and error :)
contextControl(controller:'test', action:'custom|') {
The addition of the pipe in the regex is the key to matching the null string

prevent encoding of taglib output

In my Grails app, I've defined the following tag which outputs a Map
class DataBindingTagLib {
static namespace = "bind"
def domainParamList = { attrs ->
def params = [:]
// put stuff in the map
return params
}
}
When I call this tag and store the result in a variable
<g:set var="chartParams" value="${bind.domainParamList([:])}"/>
If I inspect the type of this variable, it's a StreamCharBuffer. So it seems that the value output by the taglib is automatically being converted to this type. I tried to prevent this by changing the line above to
<g:set var="chartParams" value="${raw(bind.domainParamList([:]))}"/>
But it made no difference. Is there a way to prevent this from happening such that I can store the Map instance returned by the tag in the chartParams GSP variable? I'm not sure if this is relevant, but I have the following automatic encodings defined in Config.groovy
grails {
views {
gsp {
encoding = 'UTF-8'
htmlcodec = 'xml' // use xml escaping instead of HTML4 escaping
codecs {
expression = 'html' // escapes values inside ${}
scriptlet = 'none' // escapes output from scriptlets in GSPs
taglib = 'none' // escapes output from taglibs
staticparts = 'none' // escapes output from static template parts
}
}
}
}
You need to instruct your tag library to return an object as a result, by default tag libraries are expected to modify the output stream.
First, let the tag library know you need this particular method/closure to return an object by using the returnObjectForTags static hint. Then, simply modify the method/closure to return your object instead of modifying out. With these two changes your tag will return an object and you can use it as such.
class DataBindingTagLib {
static namespace = "bind"
static returnObjectForTags = ['domainParamList']
def domainParamList = { attrs ->
def params = [:]
// put stuff in the map
return params
}
}

Grails: Initialize variable using Configuration file

I just wanted to know that is it possible to set the value of a variable in Grails controller from the configuration file like config.groovy or some other configuration file?
For instance , my controller is as follows:
class WebsiteController {
def show(){
String user_name = "value to be fetched from configuration file"
}
}
Here, I want to set the value of user_name from the configuration file. I have no idea how to do this.
I have been given this requirement by my senior. I searched online but couldn't find anything relevant. If it is possible, please tell me the approach.
Thanks
Here is an example of properties added to the Config.groovy:
environments {
development {
tipline.email.address="joe#foo.us"
grails.logging.jul.usebridge = true
}
staging {
tipline.email.address="mailinglist#foo.us"
grails.logging.jul.usebridge = true
}
production {
tipline.email.address="mailinglist#foo.us"
grails.logging.jul.usebridge = false
// TODO: grails.serverURL = "http://www.changeme.com"
}
}
To access them in your code:
println("Email :"+grailsApplication.config.tipline.email.address)
Properties are properties =)
Properties properties = new Properties()
File propertiesFile = new File('test.properties')
propertiesFile.withInputStream {
properties.load(it)
}
def runtimeString = 'a'
assert properties."$runtimeString" == '1'
assert properties.b == '2'
Taken from Get values from properties file using Groovy
Another possibility is to inject parameters into the controller by using a property override configuration:
// Config.groovy:
website.user = "me"
beans {
'<replace by package>.WebsiteController' {
userName = website.user
}
}
// Controller:
class WebsiteController {
String userName
def show(){
//.. use userName ..
}
}
In this case you don't need grailsApplication and you don't hard code the configuration path in the Controller. Less dependencies make testing easier. :)

How to override standard behavior of ApplicationTagLib#createLink and g:link?

Background:
I have grails 1.3.7 application which uses g:createLink and g:link on many pages.
Recently I decided to make big change in url mappings - introduce preceding path element.
Currently I have: /$controller/$action?/$id?
But want to have: /$regionId/$controller/$action?/$id?
It was easy to change urlMappings, but I can't figure out how to easily change the behavior how links are built throught the application.
Basically, I don't want to go through each page and change links. But want to do this in one place.
Question
How to override ApplicationTagLib#createLink functionality so grails will use this implementation without the need of changes pages which use this tag (or function)?
Any help greatly appriciated!
I had a smilar problem. Actually you can decorate g:link tag like this.
1) TagLib
import org.codehaus.groovy.grails.plugins.web.taglib.*
class OverrideDefaultTagLib {
static namespace = "g"
def link = { attrs, body ->
def c = "1" // Get it from session or somewhere else
if (attrs.params) {
attrs.params.put("region", c)
} else {
attrs.params = [region: c]
}
def applicationTagLib = grailsApplication.mainContext.getBean('org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib')
applicationTagLib.link.call(attrs, body)
}
}
}
2) add to UrlMappings.groovy
"/$region/$controller/$action?/$id?"{}
I was unable to solve this problem in terms of OOP. I mean I can't find way how to override closure. I tried several approaches, but with no success. And documentation says that you can't override closure, you can only replace it with new implementation (please correct me if I wrong).
But (!) I was able to solve task by copy-pasting source code of ApplicationTagLib#createLink method.
I think this is brutal solution, but after 8 hours of fighting with this simple task - it's acceptable.
So finally all I need to do - is define this class, grails will immediately use it for link generation (for all views, no need to change their code):
import java.text.SimpleDateFormat;
import groovy.time.*;
import java.text.*;
import org.codehaus.groovy.grails.commons.GrailsControllerClass
import org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib;
import org.codehaus.groovy.grails.web.mapping.UrlCreator
import org.codehaus.groovy.grails.commons.ControllerArtefactHandler
import org.springframework.web.context.request.RequestContextHolder
class OverrideTagLib extends ApplicationTagLib {
def createLink = { attrs ->
// get value for regionId parameter
def regionId = regionIdFinderService.currentRegionId
// add cutsom regionId parameter
if (attrs) {
if (attrs.params)
attrs.params.put("regionId", regionId);
else {
attrs.params = ["regionId":regionId];
}
}
// process
def writer = getOut()
// prefer URI attribute
if (attrs.uri) {
writer << handleAbsolute(attrs)
writer << attrs.uri.toString()
}
else {
// prefer a URL attribute
def urlAttrs = attrs
if (attrs.url instanceof Map) {
urlAttrs = attrs.remove('url').clone()
}
else if (attrs.url) {
urlAttrs = attrs.remove('url').toString()
}
if (urlAttrs instanceof String) {
if (useJsessionId) {
writer << response.encodeURL(urlAttrs)
}
else {
writer << urlAttrs
}
}
else {
def controller = urlAttrs.containsKey("controller") ? urlAttrs.remove("controller")?.toString() : controllerName
def action = urlAttrs.remove("action")?.toString()
if (controller && !action) {
GrailsControllerClass controllerClass = grailsApplication.getArtefactByLogicalPropertyName(ControllerArtefactHandler.TYPE, controller)
String defaultAction = controllerClass?.getDefaultAction()
if (controllerClass?.hasProperty(defaultAction)) {
action = defaultAction
}
}
def id = urlAttrs.remove("id")
def frag = urlAttrs.remove('fragment')?.toString()
def params = urlAttrs.params && urlAttrs.params instanceof Map ? urlAttrs.remove('params') : [:]
def mappingName = urlAttrs.remove('mapping')
if (mappingName != null) {
params.mappingName = mappingName
}
if (request['flowExecutionKey']) {
params."execution" = request['flowExecutionKey']
}
if (urlAttrs.event) {
params."_eventId" = urlAttrs.remove('event')
}
def url
if (id != null) params.id = id
def urlMappings = applicationContext.getBean("grailsUrlMappingsHolder")
UrlCreator mapping = urlMappings.getReverseMapping(controller,action,params)
// cannot use jsessionid with absolute links
if (useJsessionId && !attrs.absolute) {
url = mapping.createURL(controller, action, params, request.characterEncoding, frag)
def base = attrs.remove('base')
if (base) writer << base
writer << response.encodeURL(url)
}
else {
url = mapping.createRelativeURL(controller, action, params, request.characterEncoding, frag)
writer << handleAbsolute(attrs)
writer << url
}
}
}
}
}
add regionId to params in createLink and g:link and grails is smart enough to match your urlmappings. i.e
${createLink(controller:'c',action:'a',id:1,params:[regionId:2])}

How do I inject new tags into a TagLib?

Lets assume that I have the following configuration in my conf/InjectionConfig.groovy file:
x {
a = { attrs, body -> out << "hello" }
b = { attrs, body -> out << "goodbye" }
}
and that I have a simple taglib such as
class XTagLib {
static namespace = "x"
}
What I want to do is that when I type <x:a /> to any of my views, it would print hello. I've already tried to inject these to the metaclass of the taglib as both property and method but neither seem to work. As an example, here's basically what I'm doing right now in a service:
public void afterPropertiesSet() throws Exception {
GroovyClassLoader classLoader = new GroovyClassLoader(getClass().classLoader)
def slurper = new ConfigSlurper(GrailsUtil.environment)
ConfigObject xConfig
try {
xConfig = slurper.parse(classLoader.loadClass('InjectionConfig'))
}
catch (e) {
e.printStackTrace()
}
xConfig.x.each({
if ( !XTagLib.metaClass.hasMetaProperty(it.key) ) {
XTagLib.metaClass.registerBeanProperty(it.key, { args ->
def attrs = args[0], body = args[1]
it.value.call(attrs, body)
}
}
})
}
Am I just doing it wrong or is this even possible currently?
Well, this
def shell = new GroovyShell() // or get a GroovyClassLoader
Class yTagLibClass = shell.evaluate("class YTagLib { static namespace = 'x' }; return YTagLib")
yTagLibClass.metaClass.a = { attrs, body -> delegate.out << 'blabla' }
grailsApplication.addArtefact(TagLibArtefactHandler.TYPE, yTagLibClass)
<x:a/> nearly worked for me - registered a tag, except for it didn't output anything. You still need to make the closure resolve out against Grails' taglib's out property.
I don't see a pretty way to do it, as there's no access to instance variables, and out is an instance variable. See Grails source, JspInvokeGrailsTagLibTag.doStartTagInternal() - you might find a way.
EDIT: I added delegate. prefix that should resolve out property of target object. Now I believe I deserve an acceptance :)
What I want to do is that when I type
to any of my views, it would
print hello
I think there's an alternative way to do what you intend: combine template & tagLib. First, create a template, then add it in your TagLib (with no complex configuration).
In my opinion, it's more simple than your approach.
Please take a look at this tutorial:
http://jan-so.blogspot.com/2008/02/example-of-template-and-taglib-with.html

Resources