ContextNotActiveException while calling #Asynchronous method of #Stateless bean - java

I am injecting a #Stateless bean in a Asynchronous Servlet and calling #Asynchronous method from the Serrvlet. In the server logs of the jboss i am not able to see any of the Exception but whhile starting the Java Mission Control ,Flight Recorder i can see ContextNotActiveExcetion whenever Servlet makes a call to the #Asyncrhonous method.
Servlet ::
#WebServlet(urlPatterns = { "/asyncservice" }, asyncSupported = true)
public class AsyncServiceServlet extends HttpServlet {
#Inject
private Service service;
protected void doPost(final HttpServletRequest request, final HttpServletResponse response)
throws ServletException, IOException {
final AsyncContext asyncContext = request.startAsync(request, response);
asyncContext.start(new Runnable() {
#Override
public void run() {
try {
service.service(asyncContext);
} catch (ContextNotActiveException | IOException e) {
e.printStackTrace();
}
});
}
Service class ::
#Stateless
public class Service {
#Asynchronous
public void service(final AsyncContext asyncContext) throws IOException {
HttpServletResponse res = (HttpServletResponse) asyncContext.getResponse();
res.setStatus(200);
asyncContext.complete();
}
}
the stack trace i can see in the flight Recorder ::
java.lang.Throwable.<init>() 4
java.lang.Exception.<init>() 4
java.lang.RuntimeException.<init>() 4
javax.enterprise.context.ContextException.<init>() 4
javax.enterprise.context.ContextNotActiveException.<init>() 4
org.jboss.weld.context.ContextNotActiveException.<init>(Enum,Object[]) 4
org.jboss.weld.manager.BeanManagerImpl.getContext(Class) 4
org.jboss.as.weld.ejb.EjbRequestScopeActivationInterceptor.processInvocation(InterceptorContext) 4
org.jboss.invocation.InterceptorContext.proceed() 4
org.jboss.invocation.InitialInterceptor.processInvocation(InterceptorContext) 4
org.jboss.invocation.InterceptorContext.proceed() 4
org.jboss.invocation.ChainedInterceptor.processInvocation(InterceptorContext) 4
org.jboss.as.ee.component.interceptors.ComponentDispatcherInterceptor.processInvocation(InterceptorContext) 4
org.jboss.invocation.InterceptorContext.proceed() 4
org.jboss.as.ejb3.component.pool.PooledInstanceInterceptor.processInvocation(InterceptorContext) 4
org.jboss.invocation.InterceptorContext.proceed() 4
org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInOurTx(InterceptorContext,TransactionManager,EJBComponent) 4
org.jboss.as.ejb3.tx.CMTTxInterceptor.required(InterceptorContext,EJBComponent,int) 4
org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(InterceptorContext)
I have been going through many posts but still the issue remain the same, please help me out .

javadoc for AsyncContext.start:
Registers the given AsyncListener with the most recent asynchronous
cycle that was started by a call to one of the
ServletRequest.startAsync() methods. The given AsyncListener will
receive an AsyncEvent when the asynchronous cycle completes
successfully, times out, or results in an error.
Implying that by the time this call to
service.service(asyncContext);
Is made, the httpservletrequest "context" may not be available and the request may even have been committed, resulting to CDI not being able to determine any '#RequestScoped' beans used by your service.
Note that AsyncContext.start registers an onEvent to be invoked when the async call is completed, or on error, not when it starts.
You would probably want to add listeners to be invoked before calling AsyncContext.start

The exception has no effect on functionality; it's handled under the hood.
The ContextNotActiveExcetion applies to #RequestScoped beans. You start double async processing with AsyncContext.start and the #Asynchronous EJB call.
The exception you see within flight recorder is to test, whether the default RequestScoped context is active and to proceed, if so. If the RequestScoped context is not active, a new EjbRequestContext is activated and associated with the thread.
You can cause a visible ContextNotActiveExcetion when you create a #SessionScoped bean and inject/access that one within your Service
MySessionScoped.java
#SessionScoped
public class MySessionScoped implements Serializable {
private int value;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
Service.java
#Stateless
public class Service {
#Inject
private MySessionScoped mySessionScoped;
#Asynchronous
public void service(final AsyncContext asyncContext) throws IOException {
System.out.println(mySessionScoped.getValue());
HttpServletResponse res = (HttpServletResponse) asyncContext.getResponse();
res.setStatus(200);
asyncContext.complete();
}
}

Related

How to #Inject into a Runnable?

I have this JAX-RS resource
#Stateless
#Path("")
public class ServerResource {
#Inject
ServerService service;
#Resource
ManagedExecutorService mes;
#PUT
#Path("/prepare")
#Produces(MediaType.APPLICATION_JSON)
public void prepare(long id) {
var info = new Info();
info.setId(id);
service.saveInitialInfo(info);
}
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#Path("/submit")
public void submit(long id, #Suspended AsyncResponse response) {
mes.execute(() -> {
var info = service.getInfo(id);
if (info == null) {
response.resume(new Exception("not found"));
}
info.doLongComputation();
response.resume(info);
});
}
And this service
#Stateless
public class ServerService {
#PersistenceContext
EntityManager entityManager;
public void saveInitialInfo(Info info) {
entityManager.persist(info);
}
public Info getInfo(long id) {
return entityManager.find(Info.class, id);
}
}
Info is an #Entity with some fields (and an #Id long id) and doLongComputation() manipulates these fields and takes time.
The client calls prepare once. This creates an Info and persists it. Now the client will perform calls to submit multiple times (with the same id). The problem is that the changes to the entity done in doLongComputation() are not "saved". On the next submit call, the entity will be in the same state that it was persisted at at first.
Because doLongComputation takes a long time I am using an AsyncResponse and executing the method inside its new thread. The problem seems to be with doing the operations inside mes.execute. If I change the method to
public void submit(long id, #Suspended AsyncResponse response) {
var info = service.getInfo(id);
if (info == null) {
response.resume(new Exception("not found"));
}
info.doLongComputation();
response.resume(info);
}
then subsequent calls to submit will actually see the changes the previous calls did.
How can I #Inject into the asynchronous response method?
I am using JavaEE 8. Iv'e seen Java EE 7 - Injection into Runnable/Callable object but that one is for JavaEE 7 and also the solution of using #Inject Instance<ServerService> service and then calling service.get() inside the Runnable does not help, probably because my classes are managed and there he creates one with new.

Spring boot Cacheable annotation -- how refresh results on every request

I have a spring boot application, which makes a large number of requests to external web services. I'm using the #Cacheable annotation in many places to cache requests. I'm trying to figure out how to cache requests on a "per-request" basis. i.e:
Suppose I have the following method which calls an external service:
#Cacheable
private List<Product> listProducts(String orgCode, String channel, String userToken) {
return externalService.listProducts(orgCode, channel, userToken);
}
When a request comes in to my spring application, it calls the listProducts method 5 times. The external service is only called once, and the cached result is used for the other 4 calls.
Now another request comes in, and calls listProducts again. The previously cached result is returned. However because this is a new request to my application, I want to refresh the results.
I feel like #Cacheable has a parameter for this that I'm just not finding.
The best way is probably to create a web Filter to clear your cache. Look at #CacheEvict(allEntries=true), you can annotate another method and call it in the Filter.
The filter could look like this:
#Component
public class CacheEvictFilter implements Filter {
private final MyService myService;
public CacheEvictFilter(final MyService myService) {
this.myService = myService;
}
#Override
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain
) throws IOException, ServletException
{
chain.doFilter(request, response);
myService.evictProducts();
}
// other methods
}
The evictProducts method could look like this:
#CacheEvict(allEntries=true)
public void evictProducts() {
log.info("Evicted all products")
}

Creating and injecting a per request scoped variable

I would like to have a variable that follows along the full lifecycle of a request in java EE.
For example it could be for a logging function, so that I can filter all log entries by request.
The key part that I want to get at is that it must be relatively easy to implement in an already existing application so if possible some sort of dependency injection that gets the variable related to the specific request.
I've tried injectiong a #RequestScoped variable, but it doesn't work since it is only scoped to the container. I would need to be able to inject the same object to different containers. Is this at all possible?
EDIT: I want something along the lines of this:
#RequestScoped
public class RequestVariables {
public String id;
}
#Stateless
public class Logger {
#Inject
private RequestVariables requestVariables;
public void log(String message) {
System.out.println(requestVariables.id + ":" + message);
}
}
#Stateless
public class Service {
#Inject
private Logger logger;
#Inject
private RequestVariables requestVariables;
public void save(String data) {
logger.log("Save");
session.save(data + requestVariables.id); //Maybe add request parameter to save aswell
}
}
public class API {
#Inject
private Service service;
#Inject
private Logger logger;
#Inject
private RequestVariables requestVariables;
#Path("/1")
#GET
public Response get(#QueryParam("data") String data) {
requestVariables.id = UUID.randomUUID().toString()
service.save(data);
logger.log("Get");
return Response.status(204).build();
}
}
Currently this is what I have experimented with:
#RequestScoped
public class RequestScope {
private int test = 0;
public RequestScope(int test) {
this.test = test;
}
public RequestScope(){}
public int getTest() {
return test;
}
public void setTest(int test) {
this.test = test;
}
}
#Provider
public class RequestScopeFilter implements ContainerRequestFilter {
#Inject
private javax.inject.Provider<RequestScope> requestScopeProvider;
#Context
private HttpServletRequest request;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
requestScopeProvider.get().setTest(42);
request.setAttribute("test", "superTest");
}
}
#Stateless
#TransactionManagement(TransactionManagementType.BEAN)
#TransactionAttribute(value=TransactionAttributeType.NOT_SUPPORTED)
public class Service {
#Context
private HttpServletRequest httpServletRequest;
#Inject
private Provider<RequestScope> requestScopeProvider;
public void test() {
RequestScope scope = requestScopeProvider.get();
String test = (String)httpServletRequest.getAttribute("test");
}
}
So when I get the scope from my service then it is a new object with test set to 0, and then it throws an NPE since httpServletRequest is null
option #1
Implement an Interceptor and set the request id as HttpServletRequest attribute:
#AroundInvoke
public Object setRequestId(InvocationContext ic) throws Exception {
HttpServletRequest request = [..] // getHttpServletRequest(ic);
request.setAttribute("request-id", UUID.randomUUID().toString());
return ic.proceed();
}
Then use HttpServletRequest everywhere you need it
#Context
private HttpServletRequest httpRequest;
option #2
If want just to filter your logs by an unique id, you can configure your Logger to print the thread name: [%t]
Example: Log4j PatternLayout
option #3
Use a custom java bean to encapsulate the request data (query param, request id etc.) and pass this bean across your application services.
public class API {
#Inject
private Service service;
#Path("/1")
#GET
public Response get(MyCustomRequestBean data) {
service.doSomejob(data);
return Response.status(204).build();
}
}
Set the request id and query param in ParamConverter:
Jax-RS ParamConverter - ParamConverterProvider method return type mismatch
You can inject a provider in your service:
#Inject
Provider<RequestVariables> vars
And then call get () to get the instance. If you try to get () in a thread outside a request scope context you'll get an exception. I would however try to structure in a way that would not allow this to happen
A solution that I found is to use ThreadLocal variables. It seems rather dirty, but it works since each request is executed on it's own thread(as far as I am aware). So this is what I got:
public class RequestScope {
private static final ThreadLocal<String> id = ThreadLocal.withInitial(() -> UUID.randomUUID().toString());
public static String get() {
return id.get();
}
}
With that I can also easily exchange the ThreadLocal to return something more specific if so desired.
And I can get the variables from pretty much anywhere, assuming that the request is not starting a different thread

Spring #Async not allowing use of autowired beans [duplicate]

This question already has an answer here:
Accessing HttpSession outside of the originally receiving thread
(1 answer)
Closed 6 years ago.
I have a fully-annotation-driven Spring Boot 1.3.5 app which has this asynchronous service which needs to autowire another service bean (And in the future it will need to autowire a repository bean, but I'm not there yet) in order to perform some business logic:
#Service
public class AsyncService {
#Autowired
public HelpingService helpingService;
#Async
public Future<String> doFoo(String someArgument)
throws InterruptedException {
Thread.sleep(3000);
System.out.println("about to do Foo "+someArgument);
String result = "";
try {
result = helpingService.getSomeStuff(someArgument);
}
catch (Exception e) {
e.printStackTrace();
}
return new AsyncResult<String>(hello);
}
}
That method above is being called from a #Controller bean, which has other endpoints (Non-async) that work as expected also using this
#Controller
public class MyController extends BaseController {
#Autowired
HelpingService helpingService;
#Autowired
AsyncService asyncService;
#RequestMapping(method=RequestMethod.GET, value={"/rest/threads/getIp/{jobId}"}, produces={"application/json"})
public ResponseEntity<?> getLog(#PathVariable("jobId") String jobId) throws InterruptedException {
asyncService.doFoo(jobId);
return new ResponseEntity<>(HttpStatus.OK);
}
}
And here's helpingService's implementation (It's an interface), calling any method works perfectly fine when I'm not doing it from the #Async method above:
#Service
#Validated
public class HelpingServiceImpl implements HelpingService {
#Autowired
HttpSession httpSession;
#Value(value="${projName}")
private String projName;
public String getServerAddress(){
AuthRegion region = (AuthRegion) httpSession.getAttribute("region");
if (region != null)
return region.getServerAddress();
else
return null;
}
#Override
public String getSomeStuff(String jobId) {
String responseString = "";
String projName = this.projName;
String serverAddress = getServerAddress(); // Code stops here with an exception
// Some code here that works fine outside this thread
return responseString;
}
}
This is the exception being caught:
about to do Foo (267)
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.
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
at org.springframework.web.context.support.WebApplicationContextUtils.currentRequestAttributes(WebApplicationContextUtils.java:309)
at org.springframework.web.context.support.WebApplicationContextUtils.access$400(WebApplicationContextUtils.java:64)
at org.springframework.web.context.support.WebApplicationContextUtils$SessionObjectFactory.getObject(WebApplicationContextUtils.java:366)
at org.springframework.web.context.support.WebApplicationContextUtils$SessionObjectFactory.getObject(WebApplicationContextUtils.java:361)
at org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler.invoke(AutowireUtils.java:307)
at com.sun.proxy.$Proxy96.getAttribute(Unknown Source)
at corp.fernandopcg.myapp.service.ThreadServiceImpl.getRundeckServerPort(ThreadServiceImpl.java:45)
at corp.fernandopcg.myapp.service.ThreadServiceImpl.getJobExecutionOutput(ThreadServiceImpl.java:65)
at corp.fernandopcg.myapp.service.AsyncService.doFoo(AsyncService.java:40)
at corp.fernandopcg.myapp.service.AsyncService$$FastClassBySpringCGLIB$$7e164220.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:115)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
I added (With some changes as I couldn't extend AsyncConfigurer at the same time as SpringBootServletInitializer, and I had to catch an exception not mentiones there) the taskExecutor part to my Application main class as follows, guided by this tutorial which does look similar to what I need, in my opinion
#SpringBootApplication
#EnableAsync
#EnableJpaRepositories(repositoryFactoryBeanClass = DataTablesRepositoryFactoryBean.class)
public class MyApplication extends SpringBootServletInitializer implements AsyncConfigurer{
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("SomeRandomLookup-");
executor.initialize();
return executor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
// TODO Auto-generated method stub
return null;
}
}
Can I tell my #Async service to be able to use other services of the application? Because if that's not possible, I don't really see the use of these threading mechanism.
This is a great illustration of why request-scope injection can be problematic. Your HelpingServiceImpl has a hidden dependency on the request-specific HttpSession, which looks like a field but is actually a proxy that is resolved by Spring on each call to always refer to the "current" request (using a thread-local variable).
The problem is that by making your call #Async, you're separating the HelpingServiceImpl invocation from the request that triggered it, and there's no longer the implicit connection of being on the same thread that would allow it to pull information from the globalish context.
The most straightforward fix is to make your dependencies explicit--instead of having your HelpingServiceImpl grab the region directly off of the HttpSession, pass the region to it as a method parameter.

EJB example for stateless and stateful beans difference [duplicate]

This question already has answers here:
When to use Stateful session bean over Stateless session bean?
(2 answers)
Closed 8 years ago.
I'm new to EJB, and I'm trying to understand the diference between Stateless and Stateful bean, so I made a simple example to test them.
#Stateless
public class Service {
private int num;
public Service(){
}
public int getNum() {
return num;
}
public void setNum() {
this.num++;
}
}
#WebServlet("/Controller1")
public class Controller1 extends HttpServlet {
#EJB
private Service serv;
public Controller1() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
serv.setNum();
response.getWriter().println(serv.getNum());
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
And the Stateful equivalent:
#Stateful
public class ServiceStateful implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private int num;
public ServiceStateful(){
}
public int getNum() {
return num;
}
public void setNum() {
this.num++;
}
}
#WebServlet("/Controller")
public class Controller extends HttpServlet {
private static final long serialVersionUID = 1L;
#EJB
private ServiceStateful serv;
public Controller() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
serv.setNum();
response.getWriter().println(serv.getNum());
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
Both examples act exactly the same, which is surprising for me. Can someone please explain what is the deal here?
Your first example returns the previously set number by chance only : the get method could have been invoked on a different bean instance. It just happened to use the same instance in this particular case, but you can't count on it.
The second one is guaranteed to return you the previously set number, provided another request doesn't call the set method before the get method is called. A stateful bean should not be injected into a servlet.
You can use instance variables of a stateless session bean, but they're not guaranteed to be preserved across method calls. If both approaches behave the same, it simply means you're probably getting the same stateless session bean instance across method calls within the same session.
You are not supposed to have member fields (aka state) in a stateless session bean. For a stateful session bean it's ok. That's the difference.
A stateful bean maintain it initial state during the conversation with the client (on or many).
A Stateless bean state can be changed (it attributes) during the conversation with the client (doesn't affect other clients)
you can see the difference if you execute multiple times!!

Categories