-
Notifications
You must be signed in to change notification settings - Fork 949
Artifact Namespaces
Up through Grails 2.1.x we have no good way of managing artifact conflicts. Artifact conflicts include things like controllers or services with the same name in separate packages. For example an application may not contain both com.demo.UserController
and com.demo.admin.UserController
. Within an application this can be managed by simply naming them differently. The bigger problem comes from using multiple plugins that provide artifacts with the same name.
Below are proposed changes for Grails 2.2.
We should identify places where the plugin name may be used effectively as a namespace for artifacts. All places where artifact names are used are candidates for attention.
When referring to a controller from a tag like g:link
, specifying a plugin name may disambiguate the reference:
<g:link controller="user" plugin="spring-security">Manage Users</g:link>
Methods that support a controller name in the form of a named argument should support a plugin name.
class DemoController {
def index() {
redirect controller: 'user', action: 'list', plugin: 'springSecurity'
}
}
Instances of service artifacts are automatically added to the spring application context. The bean name is derived from the class name so an instance of com.demo.admin.UserService
is added to the application context with the bean name userService
. For services provided by a plugin then bean name may be prefixed with a camel case version of the plugin name. For example, if the spring-security
plugin provides com.demo.admin.UserService
then the bean name would be springSecurityUserService
. It may be beneficial to alias the bean to userService
if and only if there is no other UserService
service anywhere in the application. That alias would make this more of a non-breaking change as there shouldn't be applications out there now that have multiple services with the same name so the alias would be in place for all of those situations. If the service class name begins with the plugin name then the additional prefix will not be added. For example, if the spring-security
plugin provides a service named SpringSecurityUserService
, the bean name would be springSecurityUserService
, not springSecuritySpringSecurityUserService
.
Tag Libraries already support a namespace
property. If that property is defined it should be respected. We need to figure out if it makes sense to use the plugin name as a default namespace for tags that don't express a namespace and if so, should that be in addition to or instead of putting those tags in the g
namespace.
The default name of the table that domain classes are associated with is derived from the domain class name so a com.demo.GuitarAmplifier
domain class is associated with a GUITAR_AMPLIFIER
table. The default table name could be prefixed with the plugin name. For example, if the music-equipment
plugin provides com.demo.GuitarAmplifier
, the default table name could be MUSIC_EQUIPMENT_GUITAR_AMPLIFIER
. If the domain class name begins with the plugin name then the additional prefix will not be added. For example, if the music-equipment
plugin provides a domain class named MusicEquipmentGuitarAmplifier
then the table name would be MUSIC_EQUIPMENT_GUITAR_AMPLIFIER
, not MUSIC_EQUIPMENT_MUSIC_EQUIPMENT_GUITAR_AMPLIFIER
.
It may be useful to allow this behavior to be controlled with something like grails.gorm.table.prefix.enabled = true
in Config.groovy
. The default value for this property is false
so the behavior is not enabled unless the config property is defined and assigned a value of true
. In addition to that global setting we should have the ability to turn this behavior on and off on a per plugin basis. A config property named something like grails.gorm.<plugin name>.prefix.enabled
may be used.
URL Mappings should have explicit support for mapping requests to controllers provided by plugins. We may implement this with a new plugin
token which may be used in mappings:
class UrlMappings {
static mappings = {
"/$plugin/$controller/$action" {
constraints {
// apply constraints here
}
}
"/secadmin/$controller/$action?" {
plugin = 'springSecurity'
constraints {
// apply constraints here
}
}
"/sec/$controller/$action?"(plugin: 'springSecurity')
"/manageUsers"(controller: 'user', plugin: 'springSecurity')
}
}
This is a breaking change for any existing mappings that provide explicit support for a plugin
request parameter in the mapping.