Grails
  1. Grails
  2. GRAILS-3406 Top level task: Controller Improvements
  3. GRAILS-1243

Improve support for Controllers to be placed in sub-folders/packages.

    Details

    • Type: Sub-task Sub-task
    • Status: Closed
    • Priority: Minor Minor
    • Resolution: Fixed
    • Affects Version/s: 0.3, 0.4
    • Fix Version/s: 2.2
    • Component/s: Controllers
    • Labels:
      None

      Description

      Add support for placing controllers in sub-folders/packages within the controllers folder so you can keep related controllers together, create more structured urls and make path based url security easier?

      For example:

      \grails-app\controllers\SiteController.groovy -> http://localhost:8080/sample/site
      \grails-app\controllers\admin\UserController.groovy -> http://localhost:8080/sample/admin/user
      \grails-app\controllers\admin\RoleController.groovy -> http://localhost:8080/sample/admin/role

      And views would obviously have to follow the package structure of their controller:

      \grails-app\views\admin\user\show.gsp

        Issue Links

          Activity

          Victor Volle created issue -
          Victor Volle made changes -
          Field Original Value New Value
          Link This issue is related to GRAILS-376 [ GRAILS-376 ]
          Victor Volle made changes -
          Link This issue relates to GRAILS-376 [ GRAILS-376 ]
          Hide
          Victor Volle added a comment -

          I have created this clone of GRAILS-221, because:

          This improvement as described in GRAILS-221 is only half of the enhancement, and its not leading anywhere.
          A package is a namespace and not only a name.
          The reason that controllers, domain classes should be in packages is exactly that multiple teams would be able to work in parallel if each team has its own package, and must not consider name clashes.

          Show
          Victor Volle added a comment - I have created this clone of GRAILS-221 , because: This improvement as described in GRAILS-221 is only half of the enhancement, and its not leading anywhere. A package is a namespace and not only a name. The reason that controllers, domain classes should be in packages is exactly that multiple teams would be able to work in parallel if each team has its own package, and must not consider name clashes.
          Graeme Rocher made changes -
          Fix Version/s 0.5.5-RC1 [ 13431 ]
          Fix Version/s 0.5.5-RC2 [ 13541 ]
          Hide
          Graeme Rocher added a comment -

          We're unlikely to support this for multiple reasons. First of all if you want those kinds of url patterns then you use the URL mappings feature http://grails.org/URL+mapping

          Second having name spaces at the URL level has wider implications for other parts of the system. Such as scaffolding. For example if you have a domain class foo.bar.Hello what table does it now map to? Is it foo_bar_hello by default?

          Back to URL mapping now. How does one reference a controller in a package when doing url mapping? It starts to get messy and ugly. I'm strongly of the belief that the current solution is as far as we should take it. As for multiple teams working, i've participated in many multi-team projects and never heard of one that involves no communication between teams

          Show
          Graeme Rocher added a comment - We're unlikely to support this for multiple reasons. First of all if you want those kinds of url patterns then you use the URL mappings feature http://grails.org/URL+mapping Second having name spaces at the URL level has wider implications for other parts of the system. Such as scaffolding. For example if you have a domain class foo.bar.Hello what table does it now map to? Is it foo_bar_hello by default? Back to URL mapping now. How does one reference a controller in a package when doing url mapping? It starts to get messy and ugly. I'm strongly of the belief that the current solution is as far as we should take it. As for multiple teams working, i've participated in many multi-team projects and never heard of one that involves no communication between teams
          Hide
          Victor Volle added a comment -

          Hi

          I understand that you want to keep Grails as simple as possible. So if you do not support this, it will just narrow down the number of projects where I would consider using Grails, but perhaps this is even neccesary (to keep Grails simple). But ...

          1) URL: I do not really understand the issue here. Yes it has implications, but what are the problems.

          2) Domain class => table name: Why not map foo.bar.Hello to foo_bar_Hello as the default case (as long as I can override), you do not have to use mutliple packages, Maybe all domain classes in a package share some common configurable prefix? Maybe only the last package name shall be used as part of the table name – whatever.

          3) URL (again): I have not looked too thoroughly into the URL mapping stuff, so I refrain here

          4) Multiple teams:
          no communication between teams: what a horror.
          communication that ain't necessary: what a waste of time ... that's why I prefer to have name spaces that give teams their own "fiefdom"

          Victor

          Show
          Victor Volle added a comment - Hi I understand that you want to keep Grails as simple as possible. So if you do not support this, it will just narrow down the number of projects where I would consider using Grails, but perhaps this is even neccesary (to keep Grails simple). But ... 1) URL: I do not really understand the issue here. Yes it has implications, but what are the problems. 2) Domain class => table name: Why not map foo.bar.Hello to foo_bar_Hello as the default case (as long as I can override), you do not have to use mutliple packages, Maybe all domain classes in a package share some common configurable prefix? Maybe only the last package name shall be used as part of the table name – whatever. 3) URL (again): I have not looked too thoroughly into the URL mapping stuff, so I refrain here 4) Multiple teams: no communication between teams: what a horror. communication that ain't necessary: what a waste of time ... that's why I prefer to have name spaces that give teams their own "fiefdom" Victor
          Hide
          Marc Palmer added a comment -

          I see exactly why this is a problem for the implementation. There are numerous reasons why the "name" string used internally for a class does not allow dots or similar, and that these are used in many ways to implement conventions.

          I do not think it is a big problem for grails to insist on unique class names in you grails class graph.

          Show
          Marc Palmer added a comment - I see exactly why this is a problem for the implementation. There are numerous reasons why the "name" string used internally for a class does not allow dots or similar, and that these are used in many ways to implement conventions. I do not think it is a big problem for grails to insist on unique class names in you grails class graph.
          Graeme Rocher made changes -
          Fix Version/s 0.5.5 [ 13541 ]
          Fix Version/s 0.6 [ 12699 ]
          Graeme Rocher made changes -
          Fix Version/s 1.0-RC1 [ 13341 ]
          Fix Version/s 0.6 [ 12699 ]
          Graeme Rocher made changes -
          Fix Version/s 1.0-RC1 [ 13341 ]
          Fix Version/s 1.1 [ 13674 ]
          Hide
          Simon Briman added a comment -

          1. URL: Imagine that you have an app where user's front-end and admin's back-end differ so that they're better server by different set of controllers and views. Currently what we do? We create FooController and AdminFooController, create views under adminFoo dir and add a URL mapping "/admin/foo/$action?/$id?"

          { controller = "adminFoo" }

          . Now "rinse and repeat" for bar, baz, etc... Ugly as my life.
          If we had packages we could create FooController and admin.FooController, create views under admin/foo and no URL mappings at all. Just cleaner.

          2. Domain class => table name: It feels quite organic to me to map foo.bar.Hello to foo_bar.hello by default where foo_bar is a DB schema name.

          3. Rails has it. )))

          Show
          Simon Briman added a comment - 1. URL: Imagine that you have an app where user's front-end and admin's back-end differ so that they're better server by different set of controllers and views. Currently what we do? We create FooController and AdminFooController, create views under adminFoo dir and add a URL mapping "/admin/foo/$action?/$id?" { controller = "adminFoo" } . Now "rinse and repeat" for bar, baz, etc... Ugly as my life. If we had packages we could create FooController and admin.FooController, create views under admin/foo and no URL mappings at all. Just cleaner. 2. Domain class => table name: It feels quite organic to me to map foo.bar.Hello to foo_bar.hello by default where foo_bar is a DB schema name. 3. Rails has it. )))
          Graeme Rocher made changes -
          Parent GRAILS-3406 [ 73800 ]
          Issue Type Improvement [ 4 ] Sub-task [ 7 ]
          Graeme Rocher made changes -
          Fix Version/s 1.1-beta2 [ 14752 ]
          Fix Version/s 1.1-beta1 [ 13674 ]
          Graeme Rocher made changes -
          Priority Major [ 3 ] Minor [ 4 ]
          Graeme Rocher made changes -
          Fix Version/s 1.1-beta3 [ 14824 ]
          Fix Version/s 1.1-beta2 [ 14752 ]
          Graeme Rocher made changes -
          Fix Version/s 1.1-beta3 [ 14824 ]
          Fix Version/s 1.1-RC1 [ 14929 ]
          Hide
          Graeme Rocher added a comment -

          Moving non-critical issues that aren't going to make it into 1.1 to 1.2

          Show
          Graeme Rocher added a comment - Moving non-critical issues that aren't going to make it into 1.1 to 1.2
          Graeme Rocher made changes -
          Fix Version/s 1.1-RC1 [ 14929 ]
          Fix Version/s 1.2 [ 14155 ]
          Graeme Rocher made changes -
          Fix Version/s 1.2-M1 [ 14155 ]
          Fix Version/s 1.2-M2 [ 15425 ]
          Graeme Rocher made changes -
          Fix Version/s 1.2-M3 [ 15547 ]
          Fix Version/s 1.2-M2 [ 15425 ]
          Hide
          James Frost added a comment -

          In a medium size project (for us) we have 50 odd controllers defined. Like Simon, we have to start using a naming convention for our controllers to avoid duplication (the Admin prefix is a perfect example for us too) and to help organise the source tree (which is a mess with 50 groovy files in the same folder)

          As it happens, I'm not bothered much with the domain class/GORM side of things because we don't use GORM for much - most of our Grails apps are backed with Java REST services - but I understand the issues with the name -> table name mappings. Personally I'd stick with the same pattern as currently - I'd be quite happy for admin.CustomerController to still map to the customer table by default, as long as we could override it with a static mapping or otherwise.

          Another big issue is plugins. We have a dozen or so plugins we use in the project (some ours, some third party). Since all the controllers and services etc are in the default namespace, clashes in naming is even more of an issue here and takes very careful management. If you could solve this issue for plugins (perhaps some kind of default namespace based on the plugin name?) I'd be happy to keep to the single package for the application and break lots more functionality out into individual plugins.

          James

          Show
          James Frost added a comment - In a medium size project (for us) we have 50 odd controllers defined. Like Simon, we have to start using a naming convention for our controllers to avoid duplication (the Admin prefix is a perfect example for us too) and to help organise the source tree (which is a mess with 50 groovy files in the same folder) As it happens, I'm not bothered much with the domain class/GORM side of things because we don't use GORM for much - most of our Grails apps are backed with Java REST services - but I understand the issues with the name -> table name mappings. Personally I'd stick with the same pattern as currently - I'd be quite happy for admin.CustomerController to still map to the customer table by default, as long as we could override it with a static mapping or otherwise. Another big issue is plugins. We have a dozen or so plugins we use in the project (some ours, some third party). Since all the controllers and services etc are in the default namespace, clashes in naming is even more of an issue here and takes very careful management. If you could solve this issue for plugins (perhaps some kind of default namespace based on the plugin name?) I'd be happy to keep to the single package for the application and break lots more functionality out into individual plugins. James
          Graeme Rocher made changes -
          Fix Version/s 1.2-M3 [ 15547 ]
          Fix Version/s 1.2-RC1 [ 15774 ]
          Graeme Rocher made changes -
          Fix Version/s 1.2-M4 [ 15774 ]
          Fix Version/s 1.2-RC1 [ 15959 ]
          Hide
          Victor Volle added a comment -

          I would really propose to either close this as "won't fix" or finally getting to implement it.
          Postponing it for more than two years (and this is a clone of a previous issue) is not credible.

          Show
          Victor Volle added a comment - I would really propose to either close this as "won't fix" or finally getting to implement it. Postponing it for more than two years (and this is a clone of a previous issue) is not credible.
          Hide
          Graeme Rocher added a comment -

          Its still open because it has merit, and we will get to it eventually. But it is a big change and the focus for Grails 1.2 was incremental improvements and stability. I'm there fore assigning it to Grails 2.0 since there may be breakages associated with changes this.

          Show
          Graeme Rocher added a comment - Its still open because it has merit, and we will get to it eventually. But it is a big change and the focus for Grails 1.2 was incremental improvements and stability. I'm there fore assigning it to Grails 2.0 since there may be breakages associated with changes this.
          Graeme Rocher made changes -
          Fix Version/s 1.2-RC1 [ 15959 ]
          Fix Version/s 2.0 [ 15421 ]
          Hide
          Felipe Rodrigues added a comment -

          Why not a simple namespace attribute to be configured on the controller telling it should belong to a namespace? Them the packages wouldn't have to be used for that purpose. I was thinking in something like:

          class FooController

          { ... }

          class AdminFooController

          { def namespace = "admin" }

          Then the url mappings could check that attribute and if it is there, use the indicated namespace. This is not a big change I guess.

          Show
          Felipe Rodrigues added a comment - Why not a simple namespace attribute to be configured on the controller telling it should belong to a namespace? Them the packages wouldn't have to be used for that purpose. I was thinking in something like: class FooController { ... } class AdminFooController { def namespace = "admin" } Then the url mappings could check that attribute and if it is there, use the indicated namespace. This is not a big change I guess.
          Hide
          Maxim Borkunov added a comment -

          Sometime, I believe, they will fix it.

          Show
          Maxim Borkunov added a comment - Sometime, I believe, they will fix it.
          Graeme Rocher made changes -
          Assignee Graeme Rocher [ graemerocher ]
          Hide
          Gerald Boersma added a comment -

          I hope not, because I believe Graeme is correct.

          I am familiar with Ruby, and IMO the Ruby way is broken. Automatically generating URLs based on controller packaging ties the external view of the application to the internal structure, and these should be independent.

          In Groovy, you can organize controllers / domain classes in packages and map URLs accordingly. The mapping between the external view and the internal view is under your control.

          That being said, it would be nice to extend the packaging concept to views to be able to organize folders under views in the same structure as controller packaging.

          Show
          Gerald Boersma added a comment - I hope not, because I believe Graeme is correct. I am familiar with Ruby, and IMO the Ruby way is broken. Automatically generating URLs based on controller packaging ties the external view of the application to the internal structure, and these should be independent. In Groovy, you can organize controllers / domain classes in packages and map URLs accordingly. The mapping between the external view and the internal view is under your control. That being said, it would be nice to extend the packaging concept to views to be able to organize folders under views in the same structure as controller packaging.
          Hide
          Kim A. Betti added a comment -

          "That being said, it would be nice to extend the packaging concept to views to be able to organize folders under views in the same structure as controller packaging."

          This's exactly what I'm missing.

          Show
          Kim A. Betti added a comment - "That being said, it would be nice to extend the packaging concept to views to be able to organize folders under views in the same structure as controller packaging." This's exactly what I'm missing.
          Hide
          Lauri Lüüs added a comment -

          In asp.net MVC there is this feature called Areas. It works beatufully. Developer can "package" similar features into specific area eg.

          So to separate controllers into specific area can be done with custom url mappings. But the problem is with the views. I would like to see that my project view folder would be also organized into logical structure not just huge list of folders.

          I even accept that in controller I would have some static variable to configure default view path for actual controller, that would look something like

          package admin
          class AdminSettingsController {

          def static default_view_folder = "/admin/settings"
          def index={}
          }

          and my admin index gsp location would be

          grails-app/views/admin/settings/index.gsp

          Show
          Lauri Lüüs added a comment - In asp.net MVC there is this feature called Areas. It works beatufully. Developer can "package" similar features into specific area eg. So to separate controllers into specific area can be done with custom url mappings. But the problem is with the views. I would like to see that my project view folder would be also organized into logical structure not just huge list of folders. I even accept that in controller I would have some static variable to configure default view path for actual controller, that would look something like package admin class AdminSettingsController { def static default_view_folder = "/admin/settings" def index={} } and my admin index gsp location would be grails-app/views/admin/settings/index.gsp
          Hide
          Kim A. Betti added a comment -

          I've started playing with a proof of concept plugin that implements the kind of feature Lauri is talking about.
          https://github.com/kimble/grails-view-compartments

          Show
          Kim A. Betti added a comment - I've started playing with a proof of concept plugin that implements the kind of feature Lauri is talking about. https://github.com/kimble/grails-view-compartments
          Contegix Support made changes -
          Project Import Thu Mar 24 21:22:24 CDT 2011 [ 1301019744151 ]
          Hide
          Christopher Rudolf added a comment - - edited

          Lets declare what controllers are allowed to be resolved for a given url pattern: If we restrict the controller's package for a URL mapping, then it would become very handy.

          The following solution is a bit dirty - however it works and forbids admin-controllers to appear in the root folder of the application.

           
          class UrlMappings {
          	
          	static mappings = {
          		// admin/-folder is mapped to all controllers within the com.test.admin-package
          		"/admin/$controller/$action?/$id?" {
          			controller(validator: {
          				try {
          					Class.forName('com.test.admin.'+controllerName+'Controller', true,
          						Thread.currentThread().contextClassLoader);
          				} catch(Exception e) {
          					return false;
          				}
          				return true;
          			})
                          // /-folder is mapped to all controllers within the com.test.public-package
          		"/$controller/$action?/$id?" {
          			controller(validator: {
          				try {
          					Class.forName('com.test.public.'+controllerName+'Controller', true,
          						Thread.currentThread().contextClassLoader);
          				} catch(Exception e) {
          					return false;
          				}
          				return true;
          			})
          	}
          [..]
          }
          

          If you are fine with this approach, lets make the code more clean (is there a possibility to access the controller's class, which is resolved from grails instead of verifying whether the class exists?) and add a standard validator which is like:

          	"/admin/$controller/$action?/$id?" {
          		constraints {
          			controller(package: "/com.test.admin.*/")
          		}
          	}
          	"/$controller/$action?/$id?" {
          		constraints {
          			controller(package: "/com.test.public.*/")
          		}
          	}
          
          Show
          Christopher Rudolf added a comment - - edited Lets declare what controllers are allowed to be resolved for a given url pattern: If we restrict the controller's package for a URL mapping, then it would become very handy. The following solution is a bit dirty - however it works and forbids admin-controllers to appear in the root folder of the application. class UrlMappings { static mappings = { // admin/-folder is mapped to all controllers within the com.test.admin- package "/admin/$controller/$action?/$id?" { controller(validator: { try { Class .forName('com.test.admin.'+controllerName+'Controller', true , Thread .currentThread().contextClassLoader); } catch (Exception e) { return false ; } return true ; }) // /-folder is mapped to all controllers within the com.test. public - package "/$controller/$action?/$id?" { controller(validator: { try { Class .forName('com.test. public .'+controllerName+'Controller', true , Thread .currentThread().contextClassLoader); } catch (Exception e) { return false ; } return true ; }) } [..] } If you are fine with this approach, lets make the code more clean (is there a possibility to access the controller's class, which is resolved from grails instead of verifying whether the class exists?) and add a standard validator which is like: "/admin/$controller/$action?/$id?" { constraints { controller( package : "/com.test.admin.*/" ) } } "/$controller/$action?/$id?" { constraints { controller( package : "/com.test. public .*/" ) } }
          Burt Beckwith made changes -
          Workflow jira [ 35590 ] Grails [ 40030 ]
          Burt Beckwith made changes -
          Workflow Grails [ 40030 ] Copy of Grails [ 47464 ]
          Burt Beckwith made changes -
          Workflow Copy of Grails [ 47464 ] Grails [ 54874 ]
          Burt Beckwith made changes -
          Workflow Grails [ 54874 ] Grails2 [ 62426 ]
          Burt Beckwith made changes -
          Workflow Grails2 [ 62426 ] jira [ 78803 ]
          Burt Beckwith made changes -
          Workflow jira [ 78803 ] Grails2 [ 86845 ]
          Peter Ledbrook made changes -
          Last Reviewed 01/Jan/10
          Peter Ledbrook made changes -
          Workflow Grails2 [ 86845 ] jira [ 95197 ]
          Peter Ledbrook made changes -
          Workflow jira [ 95197 ] Grails2 [ 95633 ]
          Hide
          marko.m added a comment -

          +1 for @JamesFrost suggestion for some form of plugin namespacing.

          This is a more extreme case of the inter-team issue, since co-ordination with external plugin authors is impossible. If plugins could be namespaced, then i agree that this could be a general solution for namespacing, since a single application could be encouraged to be decomposed into plugin components to enforce namespace boundaries.

          Similar to xml namespaces, maybe a simple prefix name (that maps to a more formal package/url namespace) could distinguish plugin artifacts? Maybe this could be reconciled with taglib namespaces?

          Unlike taglib namespaces it would seem that plugin namespace prefixes should be allowed to be overridden? That simple name could have a default value defined by the plugin that could then be overridden by an application that installs the plugin if a collision occurs?

          Show
          marko.m added a comment - +1 for @JamesFrost suggestion for some form of plugin namespacing. This is a more extreme case of the inter-team issue, since co-ordination with external plugin authors is impossible. If plugins could be namespaced, then i agree that this could be a general solution for namespacing, since a single application could be encouraged to be decomposed into plugin components to enforce namespace boundaries. Similar to xml namespaces, maybe a simple prefix name (that maps to a more formal package/url namespace) could distinguish plugin artifacts? Maybe this could be reconciled with taglib namespaces? Unlike taglib namespaces it would seem that plugin namespace prefixes should be allowed to be overridden? That simple name could have a default value defined by the plugin that could then be overridden by an application that installs the plugin if a collision occurs?
          Graeme Rocher made changes -
          Fix Version/s 2.2 [ 13093 ]
          Fix Version/s 3.0 [ 11042 ]
          Hide
          Jim Slattery added a comment -

          I think the limitation of UrlMappingInfo is a real issue. It chooses a controller by name only. What if a "package" name was an additional parameter? It could be optional and remain completely backwards compatible.

          By being able to specify the package name, you could solve many issues here.
          You could define a special path for a certain package: "/admin/$controller/$action?/$id?"(package:"my.example.admin")
          You could also use constraints to specify that the package must start with "my.plugin".
          If there were multiple controllers with the same name, you would have recourse to resolve them in your mapping.

          And if you left the package name unspecified, the controllers would continue to be resolved as they are today.

          Show
          Jim Slattery added a comment - I think the limitation of UrlMappingInfo is a real issue. It chooses a controller by name only. What if a "package" name was an additional parameter? It could be optional and remain completely backwards compatible. By being able to specify the package name, you could solve many issues here. You could define a special path for a certain package: "/admin/$controller/$action?/$id?"(package:"my.example.admin") You could also use constraints to specify that the package must start with "my.plugin". If there were multiple controllers with the same name, you would have recourse to resolve them in your mapping. And if you left the package name unspecified, the controllers would continue to be resolved as they are today.
          Jeff Scott Brown made changes -
          Link This issue relates to GRAILS-9300 [ GRAILS-9300 ]
          Hide
          Jeff Scott Brown added a comment -

          Some notes about the support we are building to help provide improved namespace support for controllers are available at https://github.com/grails/grails-core/wiki/Artifact-Namespaces.

          Show
          Jeff Scott Brown added a comment - Some notes about the support we are building to help provide improved namespace support for controllers are available at https://github.com/grails/grails-core/wiki/Artifact-Namespaces .
          Hide
          boillod manuel added a comment -

          I read the Artifact-Namespaces page on wiki, and I think that this feature should not be restricted to plugin.

          Below, I try to propose some alternatives solutions (to explore).

          Why not use "namespace" attribute's name instead of "plugin" ?

          //in gsp
          <g:link controller="user" namespace="com.grails.mypackage">Manage Users</g:link>
          
          //in controller
          redirect controller: 'user', action: 'list', namespace: 'com.grails.mypackage'
          
          //in url mapping
          "/$namespace/$controller/$action" {
          }
          "/secadmin/$controller/$action?" {
                      namespace = 'com.grails.mypackage'
          }
          

          For problem of bean injection, we can use a field annotation like @Namespace("com.grails.mypackage") or @Qualifier.
          I think it's better (and simpler) than prefix field's name.

          @Namespace("com.grails.mypackage")
          def userService
          

          If the namespace is not set and there was several beans with that name, use the bean from the same scope (same plugin) if exists or throw an exception.

          We can also configure aliases in Config.groovy

          //controller / url mapping / view namespace
          grails.namespaces.controller.alias = [
             'security' : ['com.grails.mypackage.*', 'com.grails.otherpackage'],
             'admin' : 'com.grails.admin'
          ]
          

          For table name, it's can be also in configuration like below:

          //domain prefix
          grails.namespaces.domain = [
             'sec_' : 'com.grails.admin.*'
          ]
          

          And for placing views in subfolders, we can use an ViewNamespace attribute:

          //in controller with static attribute
          static viewNamespace = 'admin'
          
          //in controller with annotation
          @ViewNamespace('admin')
          class UserController{
          }
          
          //in configuration
          grails.namespaces.views = [
             'admin' : 'com.grails.admin.*'
          ]
          

          It's just some ideas, but I think we can explore this way...

          Manuel

          Show
          boillod manuel added a comment - I read the Artifact-Namespaces page on wiki, and I think that this feature should not be restricted to plugin. Below, I try to propose some alternatives solutions (to explore). Why not use "namespace" attribute's name instead of "plugin" ? //in gsp <g:link controller= "user" namespace= "com.grails.mypackage" >Manage Users</g:link> //in controller redirect controller: 'user', action: 'list', namespace: 'com.grails.mypackage' //in url mapping "/$namespace/$controller/$action" { } "/secadmin/$controller/$action?" { namespace = 'com.grails.mypackage' } For problem of bean injection, we can use a field annotation like @Namespace("com.grails.mypackage") or @Qualifier. I think it's better (and simpler) than prefix field's name. @Namespace( "com.grails.mypackage" ) def userService If the namespace is not set and there was several beans with that name, use the bean from the same scope (same plugin) if exists or throw an exception. We can also configure aliases in Config.groovy //controller / url mapping / view namespace grails.namespaces.controller.alias = [ 'security' : ['com.grails.mypackage.*', 'com.grails.otherpackage'], 'admin' : 'com.grails.admin' ] For table name, it's can be also in configuration like below: //domain prefix grails.namespaces.domain = [ 'sec_' : 'com.grails.admin.*' ] And for placing views in subfolders, we can use an ViewNamespace attribute: //in controller with static attribute static viewNamespace = 'admin' //in controller with annotation @ViewNamespace('admin') class UserController{ } //in configuration grails.namespaces.views = [ 'admin' : 'com.grails.admin.*' ] It's just some ideas, but I think we can explore this way... Manuel
          Hide
          Jeff Scott Brown added a comment -

          Manuel,

          One of the things you said...

          If the namespace is not set and there was several beans with that name...

          That can never happen. There cannot be several beans with the same name in the context. Bean names within the application context have to be unique.

          Show
          Jeff Scott Brown added a comment - Manuel, One of the things you said... If the namespace is not set and there was several beans with that name... That can never happen. There cannot be several beans with the same name in the context. Bean names within the application context have to be unique.
          Hide
          boillod manuel added a comment -

          So, in the context you'll have 'namespace.controllerName', ex: 'admin.userController' and 'userController'

          And in bean injection resolution, if the field name is userController without namespace indication, you can not determine the expected bean.

          But with namespace configuration, if we configure a whole plugin with the namespace 'security' (package org.grails.security), by convention, if you are in a bean of the package org.grails.security, you can choose the bean security.userController.

          Show
          boillod manuel added a comment - So, in the context you'll have 'namespace.controllerName', ex: 'admin.userController' and 'userController' And in bean injection resolution, if the field name is userController without namespace indication, you can not determine the expected bean. But with namespace configuration, if we configure a whole plugin with the namespace 'security' (package org.grails.security), by convention, if you are in a bean of the package org.grails.security, you can choose the bean security.userController.
          Hide
          Jeff Scott Brown added a comment - - edited

          Manuel,

          I think the DI part of this only relates to service beans. The mechanism described at https://github.com/grails/grails-core/wiki/Artifact-Namespaces for handling services accounts for having multiple services with the same class name (in different packages of course) provided by the app and plugins and does so by convention, not requiring any annotations or configuration settings. Personally, I like the simplicity of that approach and sticking with autowire-by-name. One thing that proposal does not account for is having multiple services with the same name defined within the app itself or multiple services with the same name defined in the same plugin.

          Specifically as it relates to services and the injection of services into other beans (services or otherwise), does your proposal address any limitations in the wiki proposal other than the one I mention above? I realize your proposal includes issues not related to services and DI but I am focusing on that particular piece for now.

          Show
          Jeff Scott Brown added a comment - - edited Manuel, I think the DI part of this only relates to service beans. The mechanism described at https://github.com/grails/grails-core/wiki/Artifact-Namespaces for handling services accounts for having multiple services with the same class name (in different packages of course) provided by the app and plugins and does so by convention, not requiring any annotations or configuration settings. Personally, I like the simplicity of that approach and sticking with autowire-by-name. One thing that proposal does not account for is having multiple services with the same name defined within the app itself or multiple services with the same name defined in the same plugin. Specifically as it relates to services and the injection of services into other beans (services or otherwise), does your proposal address any limitations in the wiki proposal other than the one I mention above? I realize your proposal includes issues not related to services and DI but I am focusing on that particular piece for now.
          Hide
          boillod manuel added a comment -

          Yes, my proposal covers more than plugin namespaces.

          One thing to be aware with your wiki proposal: if there are two services (one inside a plugin and the other in the app) with the same name (ex: userService) , DI will depend on context.

          • In plugin, field userService will reference the service of the plugin
          • In app, field userService will reference the service of the app, and springSecurityUserService will reference the service of the plugin

          Regards

          Show
          boillod manuel added a comment - Yes, my proposal covers more than plugin namespaces. One thing to be aware with your wiki proposal: if there are two services (one inside a plugin and the other in the app) with the same name (ex: userService) , DI will depend on context. In plugin, field userService will reference the service of the plugin In app, field userService will reference the service of the app, and springSecurityUserService will reference the service of the plugin Regards
          Graeme Rocher made changes -
          Fix Version/s 2.3 [ 13311 ]
          Fix Version/s 2.2-RC1 [ 13093 ]
          Hide
          Klaus Lehner added a comment -

          this issue is now scheduled for 2.3, but was already scheduled for lot's of previous versions, but didn't get into the release.

          can we expect this feature for 2.3?

          Show
          Klaus Lehner added a comment - this issue is now scheduled for 2.3, but was already scheduled for lot's of previous versions, but didn't get into the release. can we expect this feature for 2.3?
          Hide
          Graeme Rocher added a comment -

          The fix for this was included in 2.2

          Jeff - please confirm.

          The documentation exists here

          http://grails.org/doc/2.2.x/guide/single.html#namespacedControllers

          Show
          Graeme Rocher added a comment - The fix for this was included in 2.2 Jeff - please confirm. The documentation exists here http://grails.org/doc/2.2.x/guide/single.html#namespacedControllers
          Graeme Rocher made changes -
          Assignee Jeff Brown [ brownj ]
          Hide
          Jeff Scott Brown added a comment -

          We don't support multiple controllers in the application with the same name. You cannot have com.foo.UserController and com.bar.UserController in the application. This isn't really a practical problem. Your URL mappings may contain any names you like. A real problem was the fact that for a long time if an application used a plugin with a controller name that conflicted with a controller name in the application, that would not work. The only way to fix that was to change the controller name in the app. Worse would be if the application tried to use 2 plugins and those 2 plugins had controller's whose names conflicted with each other, to which there was no solution. The namespaced controller support in 2.2 fixes that problem.

          Show
          Jeff Scott Brown added a comment - We don't support multiple controllers in the application with the same name. You cannot have com.foo.UserController and com.bar.UserController in the application. This isn't really a practical problem. Your URL mappings may contain any names you like. A real problem was the fact that for a long time if an application used a plugin with a controller name that conflicted with a controller name in the application, that would not work. The only way to fix that was to change the controller name in the app. Worse would be if the application tried to use 2 plugins and those 2 plugins had controller's whose names conflicted with each other, to which there was no solution. The namespaced controller support in 2.2 fixes that problem.
          Jeff Scott Brown made changes -
          Status Open [ 1 ] Closed [ 6 ]
          Fix Version/s 2.2 [ 13408 ]
          Fix Version/s 2.3 [ 13311 ]
          Resolution Fixed [ 1 ]
          Hide
          Klaus Lehner added a comment -

          I agree with everything about the controllers, my main point is the following sentence in the original description of this issue:

          "And views would obviously have to follow the package structure of their controller:"

          By putting controllers in different packages I can structure them as I want, but all the corresponding views are always inside one flat list, as I cannot easily put them into subdirectories. The application we are building will get up to more than 100 views, which would mean that we would end up with 100 directories under grails-app/views, which I want to avoid.

          Show
          Klaus Lehner added a comment - I agree with everything about the controllers, my main point is the following sentence in the original description of this issue: "And views would obviously have to follow the package structure of their controller:" By putting controllers in different packages I can structure them as I want, but all the corresponding views are always inside one flat list, as I cannot easily put them into subdirectories. The application we are building will get up to more than 100 views, which would mean that we would end up with 100 directories under grails-app/views, which I want to avoid.
          Hide
          Jeff Scott Brown added a comment -

          The application we are building will get up to more than 100 views, which would mean that we would end up with 100 directories under grails-app/views...

          That is incorrect. The number of directories under grails-app/views is not associated with the number of views.

          If you want to a feature like changing the directory that a controller's views are stored in, please file a JIRA for that. This JIRA wandered around and touched on more than 1 request, which is fine for discussion but complicates tracking requests and knowing when they have been satisfied.

          Thanks for your input. We appreciate it.

          Show
          Jeff Scott Brown added a comment - The application we are building will get up to more than 100 views, which would mean that we would end up with 100 directories under grails-app/views... That is incorrect. The number of directories under grails-app/views is not associated with the number of views. If you want to a feature like changing the directory that a controller's views are stored in, please file a JIRA for that. This JIRA wandered around and touched on more than 1 request, which is fine for discussion but complicates tracking requests and knowing when they have been satisfied. Thanks for your input. We appreciate it.
          Hide
          Klaus Lehner added a comment -

          You are of course right, I meant not having 100 views, but having 100 directories of views (as we have more than 100 Controllers). Anyways, I filed a new feature request for that: GRAILS-10090

          Show
          Klaus Lehner added a comment - You are of course right, I meant not having 100 views, but having 100 directories of views (as we have more than 100 Controllers). Anyways, I filed a new feature request for that: GRAILS-10090
          Hide
          Jean du Plessis added a comment -

          I've been following this issue as its something we've identified as something that would help us in many projects we build at our agency so will add my 2 cents as I don't think the fix in 2.2 resolved this issue.

          While the fix in 2.2 resolved the duplicate controller name issue with plugins this specific issue is trying to solve another problem - mainly that of ensuring cleaner structure of project assets and urls.

          This is especially relevant when you have a project with multiple campaigns in it (for instance we don't create a new project for every Facebook Page tab we build, but rather create one project per client with all their tabs in it to avoid multiple domain name and SSL certificate registrations) or when you have an admin section that you want to keep separate from your public pages both from a code and url structure pov.

          For an admin section being able to keep the controllers and views in a package called admin not only helps keep the code more structured it would also allow you to have cleaner url structures while keeping to Grails conventions and not having to resort to other workarounds.

          Example for a site with an admin section:

          Controllers /grails-app/controllers/UserController and /grails-app/controllers/admin/UserController with GSPs for actions in /grails-app/views/user/* and /grails-app/views/admin/user/*
          would map to URLs http://domain/user/* and http://domain/admin/user/*

          While there are ways to 'fake' this structure above, it would be more convenient to be able to accommodate this as part of the Grails conventions

          Show
          Jean du Plessis added a comment - I've been following this issue as its something we've identified as something that would help us in many projects we build at our agency so will add my 2 cents as I don't think the fix in 2.2 resolved this issue. While the fix in 2.2 resolved the duplicate controller name issue with plugins this specific issue is trying to solve another problem - mainly that of ensuring cleaner structure of project assets and urls. This is especially relevant when you have a project with multiple campaigns in it (for instance we don't create a new project for every Facebook Page tab we build, but rather create one project per client with all their tabs in it to avoid multiple domain name and SSL certificate registrations) or when you have an admin section that you want to keep separate from your public pages both from a code and url structure pov. For an admin section being able to keep the controllers and views in a package called admin not only helps keep the code more structured it would also allow you to have cleaner url structures while keeping to Grails conventions and not having to resort to other workarounds. Example for a site with an admin section: Controllers /grails-app/controllers/UserController and /grails-app/controllers/admin/UserController with GSPs for actions in /grails-app/views/user/* and /grails-app/views/admin/user/* would map to URLs http://domain/user/* and http://domain/admin/user/* While there are ways to 'fake' this structure above, it would be more convenient to be able to accommodate this as part of the Grails conventions
          Hide
          Jeff Scott Brown added a comment -

          Jean,

          Are you wanting something like:

          grails-app/controllers/UserController.groovy
          class UserController {
             static urlNamespace = 'foo'
          }
          
          grails-app/conf/UrlMappings.groovy
          class UrlMappings {
              static mappings = {
                  "/something/$urlNamespace/$controller/$action?/$id?" {
                      constraints {
                      }
                  }
              }
          }
          
          Show
          Jeff Scott Brown added a comment - Jean, Are you wanting something like: grails-app/controllers/UserController.groovy class UserController { static urlNamespace = 'foo' } grails-app/conf/UrlMappings.groovy class UrlMappings { static mappings = { "/something/$urlNamespace/$controller/$action?/$id?" { constraints { } } } }
          Hide
          Jean du Plessis added a comment -

          @Jeff, that would definitely help in terms of keeping url structures clean and organised, but another factor that is missing is having a structured code base - which is something I think the original request for this ticket desired.

          Now take for instance the example of Facebook tabs. What would be ideal is if you could have a project structure like this:

          grails-app
          - controllers
           - campaignx
            - TabController.groovy
           - campaigny
            - TabController.groovy
          - views
           - campaignx
            - tab
             - like.gsp
             - page.gsp
           - campaigny
            - tab
             - like.gsp
             - page.gsp
          

          The above would map to a url structure:
          http://domain/campaignx/tab/like
          http://domain/campaignx/tab/page
          http://domain/campaigny/tab/like
          http://domain/campaigny/tab/page

          What it comes down to is having the ability to have the package name determine directory and url structure. Currently while you can package controllers in different packages, it doesn't influence the view directory and url structures for that controller.

          Having a consistent convention for packaging controllers, view directory and url structure would simply things.

          Show
          Jean du Plessis added a comment - @Jeff, that would definitely help in terms of keeping url structures clean and organised, but another factor that is missing is having a structured code base - which is something I think the original request for this ticket desired. Now take for instance the example of Facebook tabs. What would be ideal is if you could have a project structure like this: grails-app - controllers - campaignx - TabController.groovy - campaigny - TabController.groovy - views - campaignx - tab - like.gsp - page.gsp - campaigny - tab - like.gsp - page.gsp The above would map to a url structure: http://domain/campaignx/tab/like http://domain/campaignx/tab/page http://domain/campaigny/tab/like http://domain/campaigny/tab/page What it comes down to is having the ability to have the package name determine directory and url structure. Currently while you can package controllers in different packages, it doesn't influence the view directory and url structures for that controller. Having a consistent convention for packaging controllers, view directory and url structure would simply things.
          Hide
          Klaus Lehner added a comment -

          yes, this is exactly what I've requested in GRAILS-10090, I would appreciate that as well

          Show
          Klaus Lehner added a comment - yes, this is exactly what I've requested in GRAILS-10090 , I would appreciate that as well
          Hide
          Jeff Scott Brown added a comment -

          I think there are reasonable requests there. This JIRA ended up conflating several things, one of which has been resolved. I prefer to leave this closed as it is a source of confusion as it is. The GRAILS-10090 request is specific and reasonable. Separate from that might be a request to support something related to URL mappings (GRAILS-10090 is only about the view directories).

          Thanks again for your input.

          Show
          Jeff Scott Brown added a comment - I think there are reasonable requests there. This JIRA ended up conflating several things, one of which has been resolved. I prefer to leave this closed as it is a source of confusion as it is. The GRAILS-10090 request is specific and reasonable. Separate from that might be a request to support something related to URL mappings ( GRAILS-10090 is only about the view directories). Thanks again for your input.
          Hide
          Jean du Plessis added a comment -

          Thanks Jeff - understand your reason for wanting to keep this request closed.
          In addition to GRAILS-10090 opened by Klaus I have opened GRAILS-10092 to deal with the controller namespace URL mapping.

          Show
          Jean du Plessis added a comment - Thanks Jeff - understand your reason for wanting to keep this request closed. In addition to GRAILS-10090 opened by Klaus I have opened GRAILS-10092 to deal with the controller namespace URL mapping.
          Hide
          boillod manuel added a comment -

          I think that a new convention could help, wihthout using url namespaces.

          If we add a 'controller.package.prefix' option in Config.groovy, we can properly handle a good convention for view directories. See the example below for details:

          Config.groovy:

          • controller.package.prefix='com.zenika'

          Controllers:

          • com.zenika.UserController
          • com.zenika.admin.UserController
          • com.zenika.public.user.AccountController

          View directories (based on this convention)

          • user/
          • admin/user/
          • public/user/account

          What do you think about it ?

          Manuel

          Show
          boillod manuel added a comment - I think that a new convention could help, wihthout using url namespaces. If we add a 'controller.package.prefix' option in Config.groovy, we can properly handle a good convention for view directories. See the example below for details: Config.groovy: controller.package.prefix='com.zenika' Controllers: com.zenika.UserController com.zenika.admin.UserController com.zenika.public.user.AccountController View directories (based on this convention) user/ admin/user/ public/user/account What do you think about it ? Manuel

            People

            • Assignee:
              Jeff Scott Brown
              Reporter:
              Victor Volle
            • Votes:
              70 Vote for this issue
              Watchers:
              67 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:
                Last Reviewed:

                Development