how to use session inside groovy thread - grails

I am new to Groovy. I want to update session variables inside a Groovy thread.
I can't put real code so I am putting sample code.
public updatename()
{
println(session["firstname"]);
Thread.start
{
session["firstname"] = "atul";
println(session["firstname"]);
}
}
I am able to access session variable outside of thread, but I am getting the following error for session inside thread
"Error 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."
Any idea how can i use session variable inside thread

Generally you can only access the session from within the scope of a web request handling thread, because you need the request context to know which session to use. A reference to the session property in a Grails controller is actually a Groovy-style call to a getSession() method injected into the class by Grails that dynamically fetches the correct session from the current request.
It may be possible to store a reference to this session in a local variable in the controller action, and then refer to that variable within the Thread.start closure:
public updatename()
{
println(session["firstname"]);
def theSession = session
Thread.start
{
theSession["firstname"] = "atul";
println(theSession["firstname"]);
}
}
but I haven't tried this myself.

Try adding following in web.xml
<web-app ...>
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
</web-app>
And it not works, you can make a simple DTO (POJO) and pass that to thread.

Related

The OAuth2 authenticated feign client doesn't support be invoked in an asynchronous method?

I am developing a spring cloud project with Feign and OAuth2.In the project, there are some time-consuming operations and some requests will be sent when these operations is finished. In order to achieve a better user experience, these operations was moved into an asynchronous method(with #Async). But there arise a problem.
I added the OAuth2FeignRequestInterceptor as a bean and has make sure that the Feign Client can work properly in the synchronous method(which thread has correct RequestAttributes in RequestContextHolder).
#Configuration
public class SomeConfiguration{
#Bean
public RequestInterceptor oauth2FeignRequestInterceptor(OAuth2ClientContext oAuth2ClientContext, BaseOAuth2ProtectedResourceDetails resource){
return new OAuth2FeignRequestInterceptor(oAuth2ClientContext,resource);
}
}
But if I move these operations into an asynchronous method, there will be throws an exception that scopedTarget.oauth2ClientContext cannot be created due to the absent of RequestContext. I have searched the stackoverflow.com and found a solution:
How to enable request scope in async task executor
With a RequestContextListener bean and these code, the RequestContextHolder belongs to the child thread would be filled with the parent thread's (the request thread) RequestAttributes.
Because the asynchronous method will cost some time before invoke the feign client, the request will be reponded before the feign client be invoked. When the request be responded, the RequestContextListener will reset the RequestAttributes in RequestContextHolder by invoke RequestContextHolder.resetRequestAttributes();(RequestContextListener.java:76) and make the request inside the RequestAttributes inactive. When it finished the time-consuming tasks and try to send something by feign client, the feign client try to get the oAuth2ClientContext from the request and throws the exception:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.oauth2ClientContext': 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: Cannot ask for request attribute - request is not active anymore!
I'm not sure if it is appropriate for OAuth2FeignRequestInterceptor to retrieve the Authorization information from the RequestContext in an asynchronous scenario.
Thank you for reading my issue and hoping for your reply.
If you're using spring, you can bind the spring security context to a sub thread.
SecurityContext context = SecurityContextHolder.getContext();
ExecutorService delegateExecutor = new ExecutorServiceAdapter(this.taskExecutor);
DelegatingSecurityContextExecutorService executor = new DelegatingSecurityContextExecutorService(delegateExecutor, context);
executor.invokeAll(tasks).stream()...
Need to define the taskExecutor bean:
#Configuration
public class ThreadConfig {
#Bean
public TaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(4);
executor.setMaxPoolSize(10);
executor.setThreadNamePrefix("task_thread");
executor.initialize();
return executor;
}
}
Last, most importantly, you need enable setThreadContextInheritable when the servlet startup:
DispatcherServlet dispatcherServlet = (DispatcherServlet)ctx.getBean("dispatcherServlet");
dispatcherServlet.setThreadContextInheritable(true);

How do I save a servicestack session in a method when not calling the method from an MVC context

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.

Error in Zuul SendErrorFilter during forward

When my Zuul Filter is unable to route to a configured URL, the 'RibbonRoutingFilter' class throws a ZuulException saying "Forwarding error" and the control goes to the 'SendErrorFilter' class.
Now when the SendErrorFilter class tries to do a forward, another exception happens during this forward call.
dispatcher.forward(ctx.getRequest(), ctx.getResponse());
The exception happening during this forward call is
Caused by: java.lang.IllegalArgumentException: UT010023: Request org.springframework.cloud.netflix.zuul.filters.pre.Servlet30WrapperFilter$Servlet30RequestWrapper#6dc974ea was not original or a wrapper
at io.undertow.servlet.spec.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:103) ~[undertow-servlet-1.1.3.Final.jar:1.1.3.Final]
at org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter.run(SendErrorFilter.java:74) ~[spring-cloud-netflix-core-1.0.0.RELEASE.jar:1.0.0.RELEASE]
at com.netflix.zuul.ZuulFilter.runFilter(ZuulFilter.java:112) ~[zuul-core-1.0.28.jar:na]
at com.netflix.zuul.FilterProcessor.processZuulFilter(FilterProcessor.java:197) ~[zuul-core-1.0.28.jar:na]
Finally when the control comes to my custom ZuulErrorFilter , i do not get the original exception. Instead the exception object i get is the one that occurs during the forward.
Update:
I found that a errorPath property can be configured to point to a Error Handling Service. If it is not configured, Zuul by default looks for a service named /error and tries to dispatch to that service. Since we did not have any service for /error , the dispatcher.forward() was throwing error.
Question
How can we skip this fwd to an error handling service ? We have a ErrorFilter to log the error. We do not want to have a error handling service.
We had faced the same issue and there is a simple solution to fix the Undertow "eating" the original exception, following my blog post:
http://blog.jmnarloch.io/2015/09/16/spring-cloud-zuul-error-handling/
You need to set the flag allow-non-standard-wrappers to true. In Spring Boot this is doable through registering custom UndertowDeploymentInfoCustomizer. Example:
#Bean
public UndertowEmbeddedServletContainerFactory embeddedServletContainerFactory() {
UndertowEmbeddedServletContainerFactory factory = new UndertowEmbeddedServletContainerFactory();
factory.addDeploymentInfoCustomizers(new UndertowDeploymentInfoCustomizer() {
#Override
public void customize(DeploymentInfo deploymentInfo) {
deploymentInfo.setAllowNonStandardWrappers(true);
}
});
return factory;
}
Now regarding the question, either way I would highly encourage you to implement your own ErrorController, because otherwise you may experience odd Spring Boot behaviour (in our setup - ralying on the default was always generating the Whitelabel error page with 200 HTTP status code - which never happens on Tomcat in contradiction) and in this way was not consumable by AJAX calls for instance.
Related Github issue: https://github.com/spring-cloud/spring-cloud-netflix/issues/524

Logging specific request header using spring security events

In my grails application, failed login attemps get logged using spring security events as shown here http://grails-plugins.github.com/grails-spring-security-core/docs/manual/guide/single.html#7.3%20Registering%20Callback%20Closures
My issue has to do with client ip retrieval. Normally, calling getRemoteAddress from details object of the event should do the job, but my case is that my application is behind a reverse proxy therefore i should get the ip from request header X-Forwarded-For.
Neither event object nor application context parameters of the closuse provide access to the request object. The global request object isn't available either.
Any ideas how to get access to headers or any other way to implement this functionality?
You can get it from RequestContextHolder, if it exists:
GrailsWebRequest request = RequestContextHolder.currentRequestAttributes()
request.getHeader("X-Forwarded-For")
Generally, as you probably know, it isn't considered a very good idea to access the web session from within Services. First of all, you break the abstraction and separation of service logic, and requests might not always be available or associated with the current thread. One way to access the session from a service is to encapsulate the HTTP session in the following manner:
class WebUtilService {
void withSession (Closure closure) {
try {
GrailsWebRequest request = RequestContextHolder.currentRequestAttributes()
GrailsHttpSession session = request.session
closure.call(session)
}
catch (IllegalStateException ise) {
log.warn ("No WebRequest available!")
}
}
}
and you would use it like this:
class MyService {
WebUtilService webUtilService
void doSomething() {
webUtilService.withSession { HttpSession session ->
log.info(session.myValue)
session.newValue = 'Possible, but should be exceptional'
}
}
}
where you could have access to the getHeader() method.
Disclaimer: the code is from Marc-Oliver Scheele's blog.

Fetching some value from message.properties in Grails

Want to fetch a value from message.properties file in grails in a job , how can I do that ??
My Job:
def execute() {
// execute task
List<String> emails = NayaxUser.findAllByEmailSent(false)*.username
emails.each {emailAddress->
mailService.sendMail {
//todo: FETCH FROM MESSAGE.PROPERTIES
to emailAddress
from FETCH FROM MESSAGE.PROPERTIES
subject FETCH FROM MESSAGE.PROPERTIES
html body.toString()
}
}
}
You can use:
g.message(code: 'my.message.code')
//or
g.message(code: 'my.message.code', args: [arg1, arg2])
You can inject the messageSource to retrieve the message:
class MyJob {
def messageSource
def execute() {
...
def message = messageSource.getMessage('message.code', ...)
...
}
}
Here's the documentation for getMessage(); you need to provide a couple more method arguments, namely args (an Object[]) and a Locale.
You can get a reference to the messageSource bean from anywhere using:
import org.codehaus.groovy.grails.commons.ApplicationHolder
import org.springframework.context.MessageSource
MessageSource messageSource = ApplicationHolder.application.mainContext.getBean('messageSource')
You can then get the messages themselves using the methods of the MessageSource interface.
Just as an addition to above answers, there could be following places where you need to implement internationalisation or fetch the message from message bundles.
views
controllers
services
Filters
Utility files(e.g. in util package or generalised exception message handling)
Special files e.g. in Shiro security rest realms
Below are the elaborate usage scenarios:
Views:- we have taglib available with message tag. Use this on views.
controllers :- message method is by default available here and locale conversion is automatically handled. See enter link description here
service: we may call taglibs inside services as below:
def myCustomTaglib = grailsApplication.mainContext.getBean('com.custom.MyCustomTagLib');
Or inject messageSource bean as
def messageSource
4.Filters / utility / Special files:- For these you may create something like below and then use it throughout.
String i18nMessage(def input,String defaultMessage) {
String[] languageCode = RequestContextHolder.currentRequestAttributes().request.getHeader("Accept-Language").split("-")
Locale locale = languageCode.length == 2 ? new Locale(languageCode[0], languageCode[1]) : new Locale(languageCode[0])
String message = defaultMessage
try {
message = messageSource.getMessage(input.code,input?.args?.toArray(),locale)
}catch (NoSuchMessageException nsme ){
log.info("No such error message--> ${nsme.getMessage()}")
}
return message
}
Also, if you get exception below:
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.
Then, you might need to add request listener to your web.xml
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
Note: web.xml is not available by default, you need to generate it from template.
These are the most common places you might need message bundle conversions.
Solution at point 4 would work in almost all cases. If you notice locale has been handled here manually which we could pass after fetching from requestHeader or request params optionally.
Hope it helps.

Resources