1

Using Grails 2.4.5 I have the following service:

class CartService {

    static scope = 'session'
    static proxy = true

    def items = []

    def getItemCount() {
        items.size()
    }

}

I want to use this service in a controller:

class CartController {

    def cartService // unique per session

    def addItem = {
        cartService.items << new CartItem(product: Product.get(params.id))
    }

}

I tried version 0.3 of the Grails scoped-proxy plugin. But I get the following error:

Error creating bean with name 'cartService': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is 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.
    Line | Method
->>  262 | run       in java.util.concurrent.FutureTask
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|   1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
|    615 | run . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^    745 | run       in java.lang.Thread
Caused by BeanCreationException: Error creating bean with name 'cartService': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is 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.
->>  262 | run       in java.util.concurrent.FutureTask
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|   1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
|    615 | run . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^    745 | run       in java.lang.Thread
Caused by 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.
->>  262 | run       in java.util.concurrent.FutureTask
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|   1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
|    615 | run . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^    745 | run       in java.lang.Thread

How do I include Service with Session Scope in Grails Controller?

Michael
  • 32,527
  • 49
  • 210
  • 370

1 Answers1

0

Looks like you might have found an issue or two (and also reported) with the plugin with Grails 2.4.x. If that is the case, you can refer to a blog post by the plugin author: Scoped Services & Proxies in Grails.

There he shows how to do it without the plugin. I gave it a shot and it works in 2.4.5.

resources.groovy:

import org.springframework.aop.scope.ScopedProxyFactoryBean

beans = {
    cartServiceProxy(ScopedProxyFactoryBean) {
        targetBeanName = 'cartService'
        proxyTargetClass = true
    }
}

Proxy is done manually, so you can remove static proxy

class CartService {
    static scope = 'session'
    def items = []

    def getItemCount() {
        items.size()
    }
}

Controller then references the proxy

class CartController {
    def cartServiceProxy 
    ... 
}

Note that one point of confusion (for me at least) was that the Controller Documentation for 2.4.x says the default scope is prototype but in the section describing Scoped Services it says that as of 2.3.x the default controller scope is singleton.

Hope this helps.

Update: To clarify a bit, the default controller scope is still prototype after Grails 2.3, but when new applications are generated by grails, configuration is generated that sets default controller scope to singleton (which is really what you should shoot for if possible like Burt says below).

Generated config in Config.groovy

// The default scope for controllers. May be prototype, session or singleton.
// If unspecified, controllers are prototype scoped.
grails.controllers.defaultScope = 'singleton'
sCrain
  • 104
  • 1
  • 6
  • Ouch, controllers are singleton now? That's going to cause a bit of confusion given up to now, you could always count on each request getting it's own controller. – billjamesdev Aug 30 '15 at 16:50
  • There's a setting in `config.groovy` that allows you to set the default. For 2.4.5 it gets generated as `grails.controllers.defaultScope = 'singleton'` so you should be able to override that here if you prefer`prototype`. – sCrain Aug 30 '15 at 17:24
  • What are you doing that requires a new controller per request? Whether the scope is singleton or prototype, each request is on its own thread, so there's no overlap on request, response, params, session, etc. As long as you don't have mutable state in your controllers (and if you do, there's is very likely a better way to do what you're doing) singletons make a lot more sense. – Burt Beckwith Aug 30 '15 at 18:16
  • @BurtBeckwith I need a Service with Session scope like a Shopping Card. How would you do that? – Michael Aug 30 '15 at 20:45
  • @BurtBeckwith You're almost certainly right, Burt; it just seemed a pretty big change at first glance, especially for upgrading. State in controllers is certainly a "Bad thing". – billjamesdev Aug 30 '15 at 21:29
  • @BillJames So could you update your answer that I would work with Grails 2.4.x? – Michael Aug 31 '15 at 09:01
  • @confile The answer is mine, but if the question is still "Include Service with Session Scope in Grails Controller?" the proxying approach is still valid, even if the Controller is a singleton. – sCrain Aug 31 '15 at 13:17
  • @sCrain Could you please explain when I should use this: ``grails.controllers.defaultScope = 'singleton'`` in Config.groovy? – Michael Sep 16 '15 at 13:38
  • I would suggest using `singleton` whenever possible. With MVC in general you want to keep your controller thin and simple so that in the end it is just accepting requests, invoking services, and ultimately constructing responses or deferring to views. If you are doing that, then as @burtbeckwith said, singletons make sense. [Grails-10113](https://jira.grails.org/browse/GRAILS-10113) is the jira where the Config.groovy default was changed, and you can see some additional discussion there. Hope this helps. – sCrain Sep 16 '15 at 20:38