Process that loads data from a remote server, triggered by a REST call. The integration test fails with:
java.lang.NullPointerException: Cannot get property 'currentSession' on null object
The loads a lot of data, so calls flush every few hundred records loaded:
protected cleanUpGorm() {
def session = sessionFactory.currentSession
session.flush()
session.clear()
}
As noted the session factory is not loaded. This is a 'helper groovy class' - neither service or controller. Do I have to now pass sessionFactory as per GrailsApplication?
The problem is with injection "sessionFactory" bean into regular groovy class.
It should be accessible using the following code:
ApplicationContext context = (ApplicationContext) ServletContextHolder.getServletContext().getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT);
SessionFactory sessionFactory = context.getBean('sessionFactory')
Session currentSession = sessionFactory.getCurrentSession()
Another technique for fetching the current session can be using grails utility class:
Session session = RequestContextHolder.currentRequestAttributes().getSession()
or
Session session = WebUtils.retrieveGrailsWebRequest().session
Related
This wasn't an issue in Grails 2 and only appears to now occur in Grails 3. Any controller that invokes an async task is unable to access the SecurityContextHolder to get logged-in user information while rendering the view....
It appears that in SecurityContextPersistenceFilter, the SecurityContextHolder.clearContext() is being called before DispatcherServlet.processDispatchResult is able to render, making rendering code unable to access logged-in user info stored in SecurityContextHolder :
try {
SecurityContextHolder.setContext(contextBeforeChainExecution);
chain.doFilter(holder.getRequest(), holder.getResponse());
}
finally {
SecurityContext contextAfterChainExecution = SecurityContextHolder
.getContext();
// Crucial removal of SecurityContextHolder contents - do this before anything
// else.
SecurityContextHolder.clearContext();
repo.saveContext(contextAfterChainExecution, holder.getRequest(),
holder.getResponse());
request.removeAttribute(FILTER_APPLIED);
if (debug) {
logger.debug("SecurityContextHolder now cleared, as request processing completed");
}
}
At first I thought the issue was related to the security context not being passed into the Promise's runnable (or some such thing), and set springsecurity.sch.strategyName = "MODE_INHERITABLETHREADLOCAL" to no avail.
Here are some screenshots of showing the debugger:
1) This line in DispatcherServlet is not yet executed. Watch statement at bottom of image shows .getAuthentication != null returns true
2) Before SecurityContextHolder being cleared out in SecurityContextPersistenceFilter:
3) After returning from ha.handle, .getAuthentication() is now null
4) getAuthentication() is now null before rendering view/result
To clarify, I am attempting to access springSecurityService.currentUser from within a custom tag library that is rendering the header of my page in a layout.
So, in a layout.gsp type file:
<header id="header" class="md-whiteframe-1dp">
<g:renderHeader/></header>
with a renderHeader definition like:
def renderHeader = { attrs, body ->
SecUser currentUser = (SecUser) accountService.activeUser
log.info("About to render header, session.id=" + session.id +
(currentUser?.userLogLabel ?: " user=not_logged_in"))
out << render(template: "/header", model: [currentUser : currentUser])
}
I hit this same issue and managed to track it down. I am assuming that you are using the spring security core plugin. The root issue is that the plugin registers an application filter without DispatcherType.ASYNC. If you look at the Spring documentation, spring security supports async. To fix it I created this BeanPostProcessor and put it in my application context.
class SpringSecurityAsyncConfigurer implements BeanPostProcessor {
#Override
Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException {
if (bean in FilterRegistrationBean && "springSecurityFilterChainRegistrationBean".equals(beanName)) {
//for some unknown reason the plugin only has this run for request and error, adding async as the spring documentation
//says this is supported
bean.setDispatcherTypes(EnumSet.<DispatcherType>of(DispatcherType.REQUEST, DispatcherType.ERROR, DispatcherType.ASYNC))
}
bean
}
#Override
Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
return bean
}
}
Are you doing this in controller or filter (and I mean 'filter' not 'interceptor')?
Because I can use it perfectly fine from a custom TokenFilter without issue.
This is why I argued heavily for moving communication away from business logic and higher up to filters and handler interceptors and to stop tying it to annotations and stuff. They keep running into these issues over and over.
I actually just released a faster version of Grails for API's that takes care of most of these communications issues yesterday for Universities
I've looked at: https://github.com/ServiceStack/ServiceStack/wiki/Sessions#saving-outside-a-service
I still don't understand how if I have a class method that I want to call from both MVC controllers and servicestack services I can save the session. Is it possible without passing a service reference?...Below is my use case:
public async Task<User> StoreAsync(User user, CustomUserSession session)
{
using (var db = DbFactory.Open())
{
await db.SaveAsync(user).ConfigureAwait(false);
}
if (session != null)
{
session.EmailConfirmed = user.EmailConfirmed;
session.ProfileImageUrl = user.ProfileImageUrl;
session.ThumbnailProfileImageUrl = user.ThumbnailProfileImageUrl;
//Following only works if I am calling the method from an MVC controller
IHttpRequest httpReq = HttpContext.Current.ToRequest();
httpReq.SaveSession(session);
//What if I call this method from a servicestack service,
//I don't really want to inject the service as an optional parameter
}
return user;
}
In order to Save a Session you need access to the current HTTP Request in order to access the Users Permanent and Temporary Session Ids Cookies attached to the incoming request.
The Session Wiki shows different ways to access the current IHttpRequest outside of a ServiceStack Service:
IHttpRequest httpReq = aspCtx.ToRequest(); //HttpContext
IHttpRequest httpReq = aspReq.ToRequest(); //MVC HttpRequestBase
IHttpRequest httpReq = listenerCtx.ToRequest(); //HttpListenerContext
//In ASP.NET hosts via the singleton
IHttpRequest httpReq = HostContext.AppHost.TryGetCurrentRequest();
Once you have access to the current IRequest you can save your typed session using the SaveSession() extension method:
httpReq.SaveSession(session);
You can only access the current request via the HttpContext.Current singleton within the context of a HTTP Request, so you need to ensure HttpContext.Current is not null. It will be null when accessed via a background thread which is likely your issue if your async method is executed on a background thread when you'd need to instead resolve the IHttpRequest from a HTTP Worker thread.
I've an MVC 5 - based web project and i using HttpSessionStateWrapper class to work with session state.
Basicaly i store some user-specific data in session state.
Here is my code (without context):
public class Util
{
private HttpSessionStateWrapper _session;
public Util()
{
_session = new HttpSessionStateWrapper(HttpContext.Current.Session);
}
public T Get<T>(string key) where T : class
{
var sessionedObject = (T)_session[key];
if (sessionedObject != null)
{
Logger.Instance.LogDebug("Object returned from session. Session Timeout=" + _session.Timeout.ToString() + " Session Id=" + _session.SessionID);
return sessionedObject;
}
return null;
}
}
The instance of Util class is created one time and serves as a static property for another singleton type.
And i've some logging here. So, timeout of session state set to 1 minute via Web.config.
But it seems session never epxires for me even within 10 minutes.
Moreover, i noted than on each request SessionId is new, but when getting data from session, the id is equal to first-time generated session id.
Session End event also never fired for me, but Session Start does.
Here is some logs:
2013-11-11 04:27:38.2578 App Starting
2013-11-11 04:27:38.6641 Session onStart. Id=0x545pyzbt4e1vzh1h1rr5d5
2013-11-11 04:27:38.6641 Object returned from session. Session Timeout=1 Session Id=0x545pyzbt4e1vzh1h1rr5d5
2013-11-11 04:28:06.5263 Session onStart. Id=ujuxasiz5hvzbv15gbvuuxt3
2013-11-11 04:28:06.5263 Object returned from session. Session Timeout=1 Session Id=0x545pyzbt4e1vzh1h1rr5d5
2013-11-11 04:29:00.3432 Session onStart. Id=jgwmmh1ubokxn3kfadevfnph
2013-11-11 04:29:00.3432 Object returned from session. Session Timeout=1 Session Id=0x545pyzbt4e1vzh1h1rr5d5
2013-11-11 04:39:25.7919 Session onStart. Id=0mocujzp4tbwwvgnkx1mn0qi
2013-11-11 04:39:25.7919 Object returned from session. Session Timeout=1 Session Id=0x545pyzbt4e1vzh1h1rr5d5
EDIT:
Thanks for replies guys! I decide to refuse using session state at all due to have no time to deep debuging this stuff, and use HttpContext.Current.Items collection, it will serve my needs
I think you get a new session on each request because you're not storing anything in the session.
Try adding the following to Global.asax.cs:
protected void Session_Start()
{
// Since .NET 2.0 ASP.NET will create a new session for each request
// unless some data is stored in the session, so here we go...
Session["dummy"] = 0;
}
Try leaving the application inactive for a few minutes (running in debug mode) and add a break point to:
protected void Session_Start() {}
in the Global.asax file, and see if this is hit when you return to the application. This should confirm that the session is actually being terminated.
You could also log the Session ID, and log this using Tracing to see when the ID changes.
If there are some serious problems in your app or you have a lot of memory leaks, your IIS app poll will restart the application and you will have exaclty this behaviour. See your system event log. IIs log.
Hello!
I am using grails jms and atmosphere plugin...
When trying to inject springSecurityService into
Jms-Atmosphere Service class, the principal/currentUser is null while there is a reference to this object (springSecurityService is not null)
//Grails Service class
class UserMessageService {
static transactional = true
static exposes = ['jms']
static destination = "queue.usermessage"
def jmsService
def springSecurityService
public def onMessage(msg) {
sleep(2000) // slow it down
log.info "sending jms mssage"
//User is null!!
User user = springSecurityService.currentUser
jmsService.send(topic:'msgevent', msg)
return null
}
}
So I am wondering...
Is it a plugin problem, or is it a problem with listening the events (As an event Listener) publicated from the jms plugin?
I have the same problem when using Atmosphere Hander as a Service using the Atmosphere plugin! In this case the atmosphere service have to be exposed to jms events also!
Please give me some ideas to deal with this... workarounds maybe... thanks
I guess there's no cookie set in your particular call. Are you using websocket? Make sure, you've got Atmosphere 1.0.0 and have the session support enabled! You will then still need to fetch the authentication from the originating request:
if(resource.writer instanceof WebsocketResponseWriter) {
AtmosphereResource resource = resource.atmosphereResource
SecurityContext sessionContext = resource.session
.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY)
}
You would then need to provide the current session context with the authentication from the session context you've found. Make sure you reset the authentication once the request has been handled.
Does this help?
I am trying to read message bundle in a job (Grails 2.0, Quartz-0.4.2):
class Job1Job {
def timeout = 5000l // execute job once in 5 seconds
def grailsApplication
def execute() {
def ctx = grailsApplication.mainContext
def bean = ctx.getBean('org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib')
println bean.message(code:'default.home.label')
}
}
And get error:
Error 2011-12-28 14:30:14,021 [quartzScheduler_Worker-5] ERROR listeners.ExceptionPrinterJobListener - Exception occured in job: GRAILS_JOBS.testappcontext.Job1Job
Message: 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.
The code works perfectly in controller and service. What I am doing wrong ?
I suspect this code run perfectly in grails 1.3.7
You're going the long way around - just use what the taglib uses, the messageSource bean:
class Job1Job {
long timeout = 5000 // execute job once in 5 seconds
def messageSource
void execute() {
println messageSource.getMessage('default.home.label', null, Locale.default)
}
}