Spring Roo
  1. Spring Roo
  2. ROO-2037

Scalability of Roo Generated Controllers

    Details

    • Type: Improvement Improvement
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Won't Fix
    • Affects Version/s: 1.1.1.RELEASE
    • Fix Version/s: 1.1.2.RELEASE
    • Component/s: WEB MVC
    • Labels:
      None

      Description

      I think some important improvements need to be made to the generated Roo Contollers.
      e.g. Run the sample Clinic.roo script. Write some code to populate the connected DB (use MySql) with a few thousand Pets and Owners.

      Observe:
      aspect PetController_Roo_Controller {
      ...
      @ModelAttribute("owners")
      public Collection<Owner> PetController.populateOwners()

      { return Owner.findAllOwners(); }

      ...}

      @ModelAttribute causes this to run even if you are just doing a direct lookup/show on a Pet, even though 'owners' are not required in the model.
      It doesn't scale well when you have thousands of entities in the DB.
      Add to persistence.xml:
      <property name="hibernate.show_sql" value="true"/>
      and you will see the vast amount of SQL generated by Hibernate.

      It's quite a problem for Roo generated MVC projects where you'd like to leverage the generated controllers in big projects.

      Duncan.

        Activity

        Hide
        Stefan Schmidt added a comment -

        Duncan, this is the reason why we have extracted this functionality into the smaller populate*() methods. It allows you to push in these methods and customize over how they function. A caching solution comes to mind.

        Show
        Stefan Schmidt added a comment - Duncan, this is the reason why we have extracted this functionality into the smaller populate*() methods. It allows you to push in these methods and customize over how they function. A caching solution comes to mind.
        Hide
        Duncan D added a comment -

        Using Push-In refactoring IS the best solution to this as it means you can take control of the populateX() methods and retain Roo's help in managing the rest of the scaffolding for the controller.
        However I did end up disabling these methods after Push-In refactoring as my tables have thousands of entities and many associations which are EAGER fetched (they are needed by the app anyway) and the loading all of these into memory (whether cached or not) causes a heap space problem and is still not scalable as my DB grows bigger.

        I guess the only solution is to use an ajax style fetch on demand for your Roo admin interface?

        Show
        Duncan D added a comment - Using Push-In refactoring IS the best solution to this as it means you can take control of the populateX() methods and retain Roo's help in managing the rest of the scaffolding for the controller. However I did end up disabling these methods after Push-In refactoring as my tables have thousands of entities and many associations which are EAGER fetched (they are needed by the app anyway) and the loading all of these into memory (whether cached or not) causes a heap space problem and is still not scalable as my DB grows bigger. I guess the only solution is to use an ajax style fetch on demand for your Roo admin interface?
        Hide
        Stefan Schmidt added a comment -

        Duncan, yes Ajax style fetching is another option. Maybe you can also leverage the pagination support if not all options need to be displayed at all times. Again, there are a number of solutions to this problem which very much depend on specifics of your application. Unless you have a specific suggestion here I'll go ahead and close this issue given, Roo offers a solution which suits many projects and also the customization hooks should you need a different approach.

        Show
        Stefan Schmidt added a comment - Duncan, yes Ajax style fetching is another option. Maybe you can also leverage the pagination support if not all options need to be displayed at all times. Again, there are a number of solutions to this problem which very much depend on specifics of your application. Unless you have a specific suggestion here I'll go ahead and close this issue given, Roo offers a solution which suits many projects and also the customization hooks should you need a different approach.
        Hide
        Stefan Schmidt added a comment -

        I'll go ahead and resolve this issue as won't fix given the discussion above.

        Show
        Stefan Schmidt added a comment - I'll go ahead and resolve this issue as won't fix given the discussion above.
        Hide
        Ihor Kaharlichenko added a comment -

        Even though the issue is already closed I'd like to put my two cents here.

        Roo offers a solution which suits many projects and also the customization hooks should you need a different approach.

        That's true, but I guess that contradicts one of Roo's goals - saving developer's time and increasing his productivity.

        Imagine a simple project with 20 entities each having a couple of dependencies. That makes the developer pushing in 80 methods (20 * 2 populate*()'s + 20 updateForm()'s + 20 createForm()'s) and hacking around this limitation.

        Also note that pushed in scaffolded method becomes no longer managed by Roo (which is sad) so a adding of a new property to an existing entity will lead to manual createForm/updateForm update as well.

        Unless you have a specific suggestion here I'll go ahead and close this issue

        I have one:

        1. Remove @ModelAttribute from all the generated populate*() methods
        2. Explicitly put all the needed model attributes in createForm and updateForm methods, since the rest of Roo-generated controller methods don't use data from populate*()

        So instead of this:

        @RequestMapping(params = "form", method = RequestMethod.GET)
        public String GoodGroupController.createForm(Model model) {
            model.addAttribute("goodGroup", new GoodGroup());
            return "goodgroups/create";
        }
        
        @ModelAttribute("goodtypes") // <-- Remove this
        public Collection<GoodType> GoodGroupController.populateGoodTypes() {
            return GoodType.findAllGoodTypes();
        }
        

        I suggest this:

        @RequestMapping(params = "form", method = RequestMethod.GET)
        public String GoodGroupController.createForm(Model model) {
            model.addAttribute("goodGroup", new GoodGroup());
            model.addAttribute("goodtypes", populateGoodTypes()); // <-- Add this; note that populate*() is still used leaving the customization hook intact
            return "goodgroups/create";
        }
        
        public Collection<GoodType> GoodGroupController.populateGoodTypes() {
            return GoodType.findAllGoodTypes();
        }
        

        The benefits of this approach are as follows:

        1. Avoid unnecessary DB queries, improved scalability
        2. Avoided the need of pushing in Roo generated code, thus letting Roo manage more code, thus save dev's time
        3. Avoided for methods other than createForm/updateForm, thus lowering request memory footprint

        I suppose that this kind of change is not too hard to implement, so if you could reconsider your decision, Stefan, I could contribute this change either with a patch or pull request.

        Show
        Ihor Kaharlichenko added a comment - Even though the issue is already closed I'd like to put my two cents here. Roo offers a solution which suits many projects and also the customization hooks should you need a different approach. That's true, but I guess that contradicts one of Roo's goals - saving developer's time and increasing his productivity. Imagine a simple project with 20 entities each having a couple of dependencies. That makes the developer pushing in 80 methods (20 * 2 populate*()'s + 20 updateForm()'s + 20 createForm()'s) and hacking around this limitation. Also note that pushed in scaffolded method becomes no longer managed by Roo (which is sad) so a adding of a new property to an existing entity will lead to manual createForm/updateForm update as well. Unless you have a specific suggestion here I'll go ahead and close this issue I have one: Remove @ModelAttribute from all the generated populate*() methods Explicitly put all the needed model attributes in createForm and updateForm methods, since the rest of Roo-generated controller methods don't use data from populate*() So instead of this: @RequestMapping(params = "form", method = RequestMethod.GET) public String GoodGroupController.createForm(Model model) { model.addAttribute("goodGroup", new GoodGroup()); return "goodgroups/create"; } @ModelAttribute("goodtypes") // <-- Remove this public Collection<GoodType> GoodGroupController.populateGoodTypes() { return GoodType.findAllGoodTypes(); } I suggest this: @RequestMapping(params = "form", method = RequestMethod.GET) public String GoodGroupController.createForm(Model model) { model.addAttribute("goodGroup", new GoodGroup()); model.addAttribute("goodtypes", populateGoodTypes()); // <-- Add this; note that populate*() is still used leaving the customization hook intact return "goodgroups/create"; } public Collection<GoodType> GoodGroupController.populateGoodTypes() { return GoodType.findAllGoodTypes(); } The benefits of this approach are as follows: Avoid unnecessary DB queries, improved scalability Avoided the need of pushing in Roo generated code, thus letting Roo manage more code, thus save dev's time Avoided for methods other than createForm/updateForm, thus lowering request memory footprint I suppose that this kind of change is not too hard to implement, so if you could reconsider your decision, Stefan, I could contribute this change either with a patch or pull request.

          People

          • Assignee:
            Stefan Schmidt
            Reporter:
            Duncan D
          • Votes:
            1 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: