FacesContext.getCurrentInstance() returns null in Runnable class - jsf

I am trying to get the FacesContext by calling FacesContext.getCurrentInstance() in the run() method of a Runnable class, but it returns null.
public class Task implements Runnable {
#Override
public void run() {
FacesContext context = FacesContext.getCurrentInstance(); // null!
// ...
}
}
How is this caused and how can I solve it?

The FacesContext is stored as a ThreadLocal variable in the thread responsible for the HTTP request which invoked the FacesServlet, the one responsible for creating the FacesContext. This thread usually goes through the JSF managed bean methods only. The FacesContext is not available in other threads spawned by that thread.
You should actually also not have the need for it in other threads. Moreover, when your thread starts and runs independently, the underlying HTTP request will immediately continue processing the HTTP response and then disappear. You won't be able to do something with the HTTP response anyway.
You need to solve your problem differently. Ask yourself: what do you need it for? To obtain some information? Just pass that information to the Runnable during its construction instead.
The below example assumes that you'd like to access some session scoped object in the thread.
public class Task implements Runnable {
private Work work;
public Task(Work work) {
this.work = work;
}
#Override
public void run() {
// Just use work.
}
}
Work work = (Work) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("work");
Task task = new Task(work);
// ...
If you however ultimately need to notify the client e.g. that the thread's work is finished, then you should be looking for a different solution than e.g. adding a faces message or so. The answer is to use "push". This can be achieved with SSE or websockets. A concrete websockets example can be found in this related question: Real time updates from database using JSF/Java EE. In case you happen to use PrimeFaces, look at
<p:push>. In case you happen to use OmniFaces, look at <o:socket>.
Unrelated to the concrete problem, manually creating Runnables and manually spawning threads in a Java EE web application is alarming. Head to the following Q&A to learn about all caveats and how it should actually be done:
Spawning threads in a JSF managed bean for scheduled tasks using a timer
Is it safe to start a new thread in a JSF managed bean?

Related

Firing CDI-Events within a thread

Within an Vaadin application I am planning to implement an asynchronous result-overview for a method.
The result overview contains a table for possible results. These results should generate while a backend-method is running asynchronous in a thread. Communication between the backend and frontend of the application is planned with using CDI-Events (information for the result will be in the CDI-Event).
I already achieved to fire CDI-Events, put them into the result-table and display the table after the method is finished. But when I execute the method within a thread (so the view is displayed and events get inserted instead of waiting to see the complete table), my CDI-Events won't fire (or get received).
Is there any way to work this out? I read about receiving CDI-Events asynchronous (blog entry), but I did not find anything about firing events within a thread...
WildFly 10.0.1.Final, Java 8, Java-EE 7 and Vaadin 7.6.6.
Thread, which should fire CDI-Events:
public class Executer implements Runnable{
#Override
public void run(){
// Here will be the backend-method invocation for firing CDI-Events
// CDI-Dummy-Event - Does not fire properly. receiveStatusEvent() does not invoke
BeanManager beanManager = CDI.current().getBeanManager();
beanManager.fireEvent(new ResultEvent("Result event example"));
}
}
Bean which receives CDI-Events
public class EventReceiver implements LoggingProvider{
public EventReceiver(){
}
public void receiveStatusEvent(#Observes ResultEvent event) {
this.info("Event received: " + event.toString());
}
}
Starting the thread with help from ManagedExecutorService
public void executeAsynchBackendMethod(){
// CDI-Dummy-Event works - receiveStatusEvent() invokes correctly
BeanManager beanManager = CDI.current().getBeanManager();
beanManager.fireEvent(new ResultEvent("Result event example"));
/* The following alternative starts a thread, but the events, which are fired in the run() method, do not take any action in the receiveStatusEvent() method */
// Getting managedExecuterService
this.managedExecuterService = (ManagedExecutorService) new InitialContext().lookup("java:comp/DefaultManagedExecutorService");
// Getting Instance of executer-Runnable (for injecting the backend-service afterwards)
Instance<Executer> executerInstance = CDI.current().select(Executer.class);
Executer executer = executerInstance.get();
// Start thread
this.managedExecuterService.submit(executer);
}
In CDI 1.2 and below, events are strictly synchronous. In CDI 2.0 there is already an implemented version of asynchronous events (in Weld) but I suppose you are stuck with 1.2.
That means (as the blog post you read suggests), you can make use of the infamous EJBs.
As for why CDI does not work in this case - I would say this is all thread-bound. In other words in that given thread where you fire the event you have no observer to be triggered.

How to get an object of session in JSF [duplicate]

I am trying to get the FacesContext by calling FacesContext.getCurrentInstance() in the run() method of a Runnable class, but it returns null.
public class Task implements Runnable {
#Override
public void run() {
FacesContext context = FacesContext.getCurrentInstance(); // null!
// ...
}
}
How is this caused and how can I solve it?
The FacesContext is stored as a ThreadLocal variable in the thread responsible for the HTTP request which invoked the FacesServlet, the one responsible for creating the FacesContext. This thread usually goes through the JSF managed bean methods only. The FacesContext is not available in other threads spawned by that thread.
You should actually also not have the need for it in other threads. Moreover, when your thread starts and runs independently, the underlying HTTP request will immediately continue processing the HTTP response and then disappear. You won't be able to do something with the HTTP response anyway.
You need to solve your problem differently. Ask yourself: what do you need it for? To obtain some information? Just pass that information to the Runnable during its construction instead.
The below example assumes that you'd like to access some session scoped object in the thread.
public class Task implements Runnable {
private Work work;
public Task(Work work) {
this.work = work;
}
#Override
public void run() {
// Just use work.
}
}
Work work = (Work) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("work");
Task task = new Task(work);
// ...
If you however ultimately need to notify the client e.g. that the thread's work is finished, then you should be looking for a different solution than e.g. adding a faces message or so. The answer is to use "push". This can be achieved with SSE or websockets. A concrete websockets example can be found in this related question: Real time updates from database using JSF/Java EE. In case you happen to use PrimeFaces, look at
<p:push>. In case you happen to use OmniFaces, look at <o:socket>.
Unrelated to the concrete problem, manually creating Runnables and manually spawning threads in a Java EE web application is alarming. Head to the following Q&A to learn about all caveats and how it should actually be done:
Spawning threads in a JSF managed bean for scheduled tasks using a timer
Is it safe to start a new thread in a JSF managed bean?

Can I use an EJB in an infinite thread

I would like to know if it's prohibited to use an EJB in an infinite thread(since it can't be given back to the container).
Something like this:
#ManagedBean(eager = true)
#ApplicationScoped
public class TestListenner {
private ResultThread result;
#PostConstruct
public void init() {
result = new ResultThread ();
Thread myThread = new Thread(result);
myThread.start();
}
public ResultThread getResult() {
return result;
}
}
And the thread:
public class ResultThread implements Runnable{
#EJB
private SomeService service;
private boolean continueWork = true;
public void run(){
while(continueWork){
service.doSomething();
//some proccessing
}
}
I'm working with EJB's since I started working with databases. I went over daofactories and the likes but I forgot about them(it was a year ago). I use them to do actions on my database when an user request a web page on my web app. But now I need to have a thread that calculate things in my database continuously to decrease the response time. If I cannot use EJB for the reason the container needs to have an handle on them, then what should I use ?
Hopefully I can use a class similar to what I'm used to use :
#Stateless
public class SomeServiceImpl implements SomeService {
#PersistenceContext(unitName = "my-pu")
private EntityManager em;
#Override
public void updateCategory(SomeClass theclass) {
em.merge(theclass);
}
}
Edit: The first answer by BalusC in this topic seems to imply that spawning threads in a ManagedBean wouldn't be dangerous in a case where no additional threads could be spawned. Since my bean is ApplicationScoped, which the web-app uses 1 and only 1 instance of it to do background work on the database (I've actually like a TOP 100 "posts" table that needs to be continually recalculated over time so I can query the table -with another bean- to have a fast answer).
What you have now won't work for at least one reason:
You can't inject resources into non-managed components. For the #EJB annotation to work, ResultThread ought to be a managed bean, and injected by the container. That means, that you must at least use CDI to inject it, rather than the new ResultThread you have now. What will work will look something like:
#Inject
private ResultThread result;
This way, the container gets in on the action.
The bottom line however, is that there are better ways of doing what you appear to be trying to do.
An EJB Timer
The new ManagedExecutor
Async EJBs
It may also interest you to know that EJBs are not allowed to spawn their own threads; in fact, it's frowned upon to do any handmade threading in the container. Why? The container is a managed environment - one where memory and concurrency have already been well thought out and designed. Your handspun thread breaks that model and any guarantees that the container may have been able to give you on your beans and other app components
Related:
Why is spawning threads in Java EE container discouraged?
You can't use your own Threads on Java EE container.
http://www.oracle.com/technetwork/java/restrictions-142267.html#threads
The Java EE spec provide TimerServices for this kind of work.
https://docs.oracle.com/javaee/6/tutorial/doc/bnboy.html

CDI - ContextNotActiveException - WebBeans context with scope type annotation #RequestScoped does not exist within current thread

Environment : WAS 8.0.0.10
CDI : 1.0 (Implementation OpenWebBeans)
Use Case: Server is executing the Java class asynchronously via TimerManager. I am trying to inject the cdi bean with Request scope into the class but when any method is called on the injection, below is the stack trace i am getting. If i use the Applicationscope instead of RequestScope in the injection, Code works fine.
Upon investigating the issue, i found that Request and Session context will not be active for the threads initiallized asynchronously by the container. Is there some way i can initialize the request and session context?
Error :
javax.enterprise.context.ContextNotActiveException: WebBeans context with scope type annotation #RequestScoped does not exist within current thread**
at org.apache.webbeans.container.BeanManagerImpl.getContext(BeanManagerImpl.java:358)
at org.apache.webbeans.intercept.NormalScopedBeanInterceptorHandler.getContextualInstance(NormalScopedBeanInterceptorHandler.java:124)
at org.apache.webbeans.intercept.NormalScopedBeanInterceptorHandler.invoke(NormalScopedBeanInterceptorHandler.java:95)
at com.ford.it.processcontrol.TestJob3_$$_javassist_22.executeJobCB(TestJob3_$$_javassist_22.java)
I'm assuming you already have this, or something alike somewhere:
CdiContainer cdiContainer = CdiContainerLoader.getCdiContainer();
cdiContainer.boot();
ContextControl contextControl = cdiContainer.getContextControl();
Then, somehow you have access to the ContextControl instance. Then you can start the context wherever you need it, just remember to stop it when it's no longer needed
try{
//start
contextControl.startContext(RequestScoped.class);
// do stuff
}catch(Exception e){}
finally{
//stop
contextControl.stopContext(RequestScoped.class);
}
This is working for me in some asynced classes.
Hope it helps.
regards!

Timing out from a bean

I want my session to timeout after a given interval of time. In web.xml I've been using code like:
<session-config>
<session-timeout>20</session-timeout>
</session-config>
where 20 is the timeout period in minutes, which works correctly.
What I would like to do is to do it programatically using code like this inside one of my beans as follow:
#ManagedBean(name="login")
#SessionScoped
public class MyLoginBean implements HttpSessionListener, Serializable {
// private variables etc.
HttpServletRequest request;
HttpSession session = request.getSession();
// Constructor
public MyLoginBean() {
session.setMaxInactiveInterval(1200);
}
// The rest of the code
}
where the timeout here is 1200 seconds, i.e. 20 minutes. Unfortunately, on opening up a browser to look at the application, it fails with the message:
com.sun.faces.mgbean.ManagedBeanCreationException: Cant instantiate class: com.csharp.MyLoginBean.
Followed by:
java.lang.NullPointerException
What am I doing wrong here? I know that setMaxInactiveInterval() refers to the particular session, which in this case is the login bean, rather than everything, which is what the code in web.xml file specifies. I have several beans, but timing out the login bean is the only one that matters.
I'm using JSF 2.0 with Glassfish 3.1.1 and Eclipse Indigo, so some advice would be very much appreciated.
The NullPointerException has an extremely simple cause. It's one of the most simplest exceptions. To learn about the cause of an arbitrary exception, just look in its javadoc. All Java exceptions have their causes explained in the javadoc. Here's an extract of the javadoc of NullPointerException:
Thrown when an application attempts to use null in a case where an object is required. These include:
Calling the instance method of a null object.
Accessing or modifying the field of a null object.
Taking the length of null as if it were an array.
Accessing or modifying the slots of null as if it were an array.
Throwing null as if it were a Throwable value.
Applications should throw instances of this class to indicate other illegal uses of the null object.
Your problem is caused by point 1. Here,
HttpServletRequest request;
HttpSession session = request.getSession();
you're trying to invoke getSession() method on null instead of a concrete HttpServletRequest instance. In fact, you should have obtained the HttpServletRequest via ExternalContext#getRequest() and assigned it to request.
However, you've bigger problems: you should absolutely not get hold of the current servlet request as a property of a session scoped bean (which lives longer than the HTTP request!). You should get it inside the thread local scope (i.e. wholly inside the constructor or the method block). You should also not let your JSF managed bean implement the HttpSessionListener. This makes no utter sense. You'd end up with 2 instances, one created as listener by the container and another one created as managed bean by JSF.
Just thus should do:
#ManagedBean(name="login")
#SessionScoped
public class MyLoginBean implements Serializable {
public MyLoginBean() {
HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession();
session.setMaxInactiveInterval(1200);
}
// ...
}
Or, if you're using JSF 2.1, use the one provided by ExternalContext:
FacesContext.getCurrentInstance().getExternalContext().setSessionMaxInactiveInterval(1200);

Resources