Using spring session scope without session - java

I have web application where I defined session scoped UserDetail. The problem is that I also have some Quartz jobs that should use UserDetail bean. When job is run I get:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.userDetails': 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.
Inside job I need to inject some "technical user" details. Is it possible to properly handle situation when session is not present? Maybe any conditional injection?
EDIT 1
To clarify. I dont want to have session in my job service. This job modifies data and some audit log based on user data is saved to database. Normally user data comes from session but in job I need to provide some "static" technical user data. Any ideas?

Quartz does not know anything about "sessions", so if you want your background job to know the user that submitted the job, you have to pass that information to the job, likely in the DataMap of the trigger.

Related

Spring Boot Request-scoped bean is re-used for multiple requests

Our Spring Boot web application defines a bean that, upon construction, writes a unique ID to the SLF4J MDC (mapped diagnostic context) in order to make it clear in the logs which request caused which log message.
Therefore the bean is request-scoped, i.e. we expect it to only exist as long as exactly one HTTP request is serviced and then it should be destroyed by Spring Boot.
Upon a new request, a new instance should be created, hence there should be a unique REQUEST_ID for every request.
#Component
#Scope(WebApplicationContext.SCOPE_REQUEST)
public class RequestContext {
public RequestContext() {
putInMdc(REQUEST_ID, UUID.randomUUID().toString());
}
...
However, what we observe is lots of unrelated log messages all having the same REQUEST_ID, which can only mean that the constructor of RequestContext is not called between those requests.
All the log messages belong to the same thread ID. I know that Tomcat usually re-uses threads for multiple requests, but shouldn't Spring Boot re-create a request scoped bean anyway as soon as the request is serviced?

How to deal with thread in background processing java spring boot?

I want to download file after query but the time is too long, so my company said I should let the process in background.
For that I create thread when user call method, it will generate file and send to email of customer.
But the problem is about my thread, I also test function for sendemaildownload (it also includes the function which I use to query), I'm quite sure this problem from the way I create the thread.
This is what it says to me when I'm logging the error on creating the thread:
Exception in thread "Nathan-Transportation1" 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: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
Is there any way to fix it? I want to understand why it happend when I create my thread pool.
Try using #Async annotation.
For more information see here
This error message indicates that you are attempting to access request-scoped data (for example, request attributes) outside of the context of an HTTP request.
You can try the following solutions to this problem:
To expose the current request and make it accessible to your code,
use a RequestContextListener or RequestContextFilter.
To execute tasks in a background thread, use Spring's TaskExecutor interface, which will handle the necessary context management for you.
Here are some links that may be of interest to you:
RequestContextListener
RequestContextFilter
TaskExecutor

Spring Boot: Unable to access the request scope bean in Spring Scheduler

In my Spring Boot application, i've a Scheduler task which executes for every one hour. In the scheduler method trying to access the request-scope bean. Always getting the exception org.springframework.beans.factory.BeanCreationException.
Here is the code sample.
#Data
public class TestVo {
private String message = "Hello";
}
#Bean
#Scope(value="request", proxyMode=ScopedProxyMode.TARGET_CLASS)
public TestVo testVo() {
return new TestVo();
}
Accessing the above created bean in scheduler method as below,
#Autowired
private TestVo testVo;
#Scheduled(cron="0 0 * * * *")
public void greetings() {
System.out.println(testVo.getMessage()); // accessing request scope bean
}
getting below exception with above code,
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'scopedTarget.scheduledJobTaskExecutor': Scope
'request' 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: In this case, use
RequestContextListener or RequestContextFilter to expose the current
request.
The request scoped beans are bounded to specific requests. Every time a request comes, a new instance will be created and after the request finished it will be destroyed. The request is bounded to a thread and use that thread to process the request (in non reactive environment). Even if it was possible, the scheduler wouldnt know, which request object it should use in this situation. Consider you have 100 active request when the scheduled job starts to run, how it should choose one? Or if there arent any active request (so no instance hold by the context?). You can inject request scope into singleton via proxy because the singleton method call will be handled on the same request thread, but the scheduled job use its own thread pool, which not bounded to any requests.
Maybe now you can see the problem using request scoped bean in the scheduler.
If you want to use the same logic in the scheduler and in request scoped beans, you can for example extract it into a superclass.

Java EE Request scope and Asynchronous

I am attempting to time an log performance using an interceptor.
#LogPerformance
#Interceptor
public class PerformanceInterceptor {
The times are stored in a request scoped bean. When the the request has finished the times are written to a log file.
When I changed several of the logged methods to be asynchronous, the logging for those operations stopped being output.
#Asynchronous
#LogPerformance
public Future<String> getString() {
I believe the new EJB thread is defining a new request scope. I can log output from the interceptor and see the request scoped object, but there are two different addresses attached to the objects. One address for the http thread and a different address for the EJB thread.
Is there a way to allow the interceptors from the async methods to write to the object in the http request scope? Is there another way to get the data back into the parent scope?
The container will propagate the javax.ejb.EJBContext to the thread that executes the asynchronous method.
You can inject this EJBContext into your interceptor and stash any state (such as your request scoped bean) that you want into it via javax.ejb.EJBContext.getContextData().

Combine Resteasy async fail to inject SessionScoped and RequestScoped bean with CDI

I am working on a issue related to async job in Reasteasy (http://docs.jboss.org/resteasy/docs/2.3.1.GA/userguide/html_single/index.html#async_job_service).
I post a request adding ?asynch=true to the url, and the job is then run asynchronously, but when it runs, it works fine with #ApplicationScoped or #Singleton annotated bean, but it cannot access bean of class declared with #RequestScoped annotation and I always run into this error :
org.jboss.weld.context.ContextNotActiveException: WELD-001303 No active contexts for scope type javax.enterprise.context.RequestScoped
at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:664)
at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:77)
at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:87)
at com.examplecompany.exampleproject.multitenancy.org$jboss$weld$bean-flat-ManagedBean-class_com$examplecompany$exampleproject$multitenancy$PersistenceContext_$$WeldClientProxy.setDb(org$jboss$weld$bean-flat-ManagedBean-class_com$examplecompany$exampleproject$multitenancy$PersistenceContext$$_WeldClientProxy.java)
at com.examplecompany.exampleproject.auth.oauth.secure.OAuthDelegate.filterHttp(OAuthDelegate.java:115)
at com.examplecompany.exampleproject.auth.oauth.secure.AuthorizationInterceptor.preProcess(AuthorizationInterceptor.java:59)
at com.examplecompany.exampleproject.auth.oauth.secure.org$jboss$weld$bean-flat-ManagedBean-com$examplecompany$exampleproject$auth$oauth$secure$AuthorizationInterceptor$#javax$enterprise$context$ApplicationScoped()#javax$ws$rs$ext$Provider()#org$jboss$resteasy$annotations$interception$SecurityPrecedence()#org$jboss$resteasy$annotations$interception$ServerInterceptor()${com$examplecompany$exampleproject$auth$oauth$secure$AuthorizationInterceptor$oauthDelegate$#javax$inject$Inject()$$}_$$_WeldClientProxy.preProcess(org$jboss$weld$bean-flat-ManagedBean-com$examplecompany$exampleproject$auth$oauth$secure$AuthorizationInterceptor$#javax$enterprise$context$ApplicationScoped()#javax$ws$rs$ext$Provider()#org$jboss$resteasy$annotations$interception$SecurityPrecedence()#org$jboss$resteasy$annotations$interception$ServerInterceptor()${com$examplecompany$exampleproject$auth$oauth$secure$AuthorizationInterceptor$oauthDelegate$#javax$inject$Inject()$$}_$$_WeldClientProxy.java)
at org.jboss.resteasy.core.ResourceMethod.invokeOnTarget(ResourceMethod.java:247)
at org.jboss.resteasy.core.ResourceMethod.invoke(ResourceMethod.java:222)
at org.jboss.resteasy.core.ResourceMethod.invoke(ResourceMethod.java:211)
at org.jboss.resteasy.core.SynchronousDispatcher.getResponse(SynchronousDispatcher.java:525)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:502)
at org.jboss.resteasy.core.AsynchronousDispatcher.invokeSuper(AsynchronousDispatcher.java:227)
at org.jboss.resteasy.core.AsynchronousDispatcher$1.call(AsynchronousDispatcher.java:267)
at org.jboss.resteasy.core.AsynchronousDispatcher$1.call(AsynchronousDispatcher.java:259)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:680)
This error do not occur if I post the same request not adding ?asynch=true.
I further investigated the issue and wrote the following lines in my code
try {
Context context = beanManager.getContext(RequestScoped.class);
} catch (ContextNotActiveException e) {
logger.info("Oops the context does not exists, we are in bad sh*t",e);
}
If I'm in async mode, the ContextNotActiveExceptionis always thrown, and the log have the same exception message WELD-001303 No active contexts for scope type javax.enterprise.context.RequestScoped.
So I guess that when the task is launched async mode, the two context Session and Request are not created, and thus my bean defined in these scope are inaccessible.
I raised a ticket into Resteasy Jira for this: https://issues.jboss.org/browse/RESTEASY-682
According the to spec, section 6.7.2, the SessionScope is not available for web service requests. You'll have to create a new persistent scope and use that. The problem with web service calls (JAXRS or JAXWS) and the session is that there is no guaranteed way to track the session from one request to the next. Clients aren't required to send back cookies, or use a request param. If your service requires and enforces this, then you'll have to either create a new scope and context backing, or use the CDI implementation's API to manually start and bind to the session scope.

Categories