How to run a long running process in JSF without facing "Connection Failed" error in browser [duplicate] - jsf

I want to execute a stored proc by clicking on a button developed in JSF and Java. The proc takes roughly around 30 minutes in execution.
When the user clicks on this button, s/he should get a default message like -
Data is being processed. Kindly login after 60 minutes to check the data.
Now when we click on the button, the UI Page hangs for the time when the proc is getting executed.
Is there a workaround to show this default message and run the proc in the backend?

Just trigger an #Asynchronous EJB method. It'll fire and forget a separate thread and the bean action method will immediately return.
#Named
public class Bean {
#EJB
private Service service;
public void submit() {
service.asyncDoSomething();
// Add message here.
}
}
#Stateless
public class Service {
#Asynchronous
public void asyncDoSomething() {
// ...
}
}
See also:
Is it safe to start a new thread in a JSF managed bean?
How can server push asynchronous changes to a HTML page created by JSF?

You can call a method on click of button which can use Future or FutureTask, available in the java.util.concurrent package. Former is an interface, the latter is an implementation of the Future interface.
By using "Future" in your code, your asynchronous task will be executed immediately with the promise of the result being made available to the calling thread in the future.
Have a look at this link: Is it safe to start a new thread in a JSF managed bean?
Also have a look at this link: https://codereview.stackexchange.com/questions/39123/efficient-way-of-having-synchronous-and-asynchronous-behavior-in-an-application

Related

Where should I create my ConnectionPool in a JSF application?

I am new to JSF/Facelets and I am creating an application that does the usual CRUD operations over a (No SQL) database. The database has an API that allows the creation of a pool of connections, and then from this object my operations can take and release connections. I suppose this pool has to be created only once for the whole application when it is deployed, be shared (as static?) and closed once the application is destroyed. Is my approach correct? What is the best practice to do this? I have no idea of where I should place my code and how I should call it.
With my old SQL database I used to configure a "testOnBorrow" and a "validationQuery" in the context.xml Resource so I didn't have to create an explicit pool programmatically.
I found two great tutorials (here and here) but I can't figure out from them where to put the code that creates the pool.
Note: I know this might be only a Servlet problem, but I am tagging it as JSF since I don't know if there is a way to do this in JSF (like an application scoped bean). Thanks.
EDIT
Looking at the fact that I cannot find a JAR with a DataSource for the database to be loaded via context.xml, perhaps my question should be more specific: where can I run code once, when a JSF application is deployed and where can I run code when a JSF application is destroyed?
You can implement a weblistner( i.e ServletContextListener). and can use contextInitialized , contextDestroyed method of that to create and destroy your connection pool
Sample :
#WebListener
public class ContextWebListner implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent event) {
// initialize connection pool.
}
#Override
public void contextDestroyed(ServletContextEvent event) {
// Destroy connection pool.
}
}

How to design communication from a backend server to the frontend using JavaEE (EJB, JSF, PrimeFaces)

Normally, a frontend such as a web application (e.g. JSF) is used to retrieve data from a system and display it. User interaction is required: a user pulls up a website and e.g. clicks a button which in turn triggers a whole round trip process (view calls controller, controller informs model, model updates and notifies view via controller again).
In my setup I don't have any user interaction because my webapp is a view only. No user can do any CRUD actions (except Read). The "user interaction" comes so to speak from my backend: This system runs the entirety of business logic and receives user interactions through other channels than the webapp.
However, all changes within the backend need to be somehow pushed into the webapp frontend.
I am using JavaEE, more precisely EJB 3.2, JSF 2.2 and PrimeFaces 5.1 (as well as JMS 2.x, WildFly 8.2, OmniFaces 2.0)
My backend communicates changes via JMS. I defined a MessageListener within my webapp that listens to all incoming changes. These changes are pushed into the model (EJBs).
As far as my knowledge goes should a model never know anything about it's view: the model is completely agnostic to the view. In JavaEE terms this means that my EJBs (model) should not inject any ManagedBeans (controller).
Now here is my question: How should the model inform the controller/view about changes, so that they get reflected within the view?
Am I forced to use something like CDI Events?
Or in case of PrimeFaces, should I use PrimeFaces Push (WebSocket implementation using Atmosphere) that kinda simulates a user interaction? In other words, should my JMS MessageListener directly push the changes to all clients (browsers) via WebSocket and then use AJAX to simulate an user interaction (which in turn does nothing else than what a "normal" user would trigger in the webapp)?
Or how about the old fashioned way according to Observer Pattern: Every managed bean that needs to be notified I add as listener to the EJB with help of #PostConstruct and also make sure that the listener gets removed with #PreDestroy?
We found a solution doing it in a "hybrid" mode. Here is what we came up with:
Observer Pattern
We used the classic Observer Pattern: A managed bean adds itself as listener to an EJB, which in turn is updated by the JMS message listener. Therefore, we made use of the #PostConstruct to add a listener as well as #PreDestroy to remove listener respectively whenever the managed bean gets created/destroyed.
In other words, whenever the model gets updated, it informs its listeners, which are the managed beans (controller). But this doesn't yet update the view. Here comes the hybrid mode into play:
PrimeFaces Push
Once the model (EJB) is updated it has to push a notification to it's web clients via PrimeFaces Push. This way all clients know they have to go grab the changes:
#ManagedBean(name = "notifier")
#ApplicationScoped
public class MarketDataPushNotifier implements Serializable {
private final Logger log = LoggerFactory.getLogger(MarketDataPushNotifier.class);
public final static String CHANNEL = "/notify";
private final EventBus eventBus = EventBusFactory.getDefault().eventBus();
public MarketDataPushNotifier() {
// bean instantiation only
}
public void notifyListeners() {
log.info("Sending UI update notification...");
eventBus.publish(CHANNEL, true);
}
}
Of course one can design the notify channel more fine grained. In the view (facelet) do:
<p:remoteCommand name="updateTable" actionListener="#{bean.onUpdate}" update="table" process="#this" />
<!--table snippet ommitted-->
<p:socket onMessage="handleMessage" channel="/notify" autoConnect="true"/>
<script type="text/javascript">
function handleMessage(update) {
if (update) {
updateTable();
}
}
</script>
Hope that helps...

JSF 2.0, URL redirection to external website, after which some operation needs to be done on the original window

I am building a JSF 2.0 application. Basically this is the flow :
Perform some steps (pre conditions)
Redirect to external server based on results of preconditions
Perform some post redirection steps (update status flags etc)
The question I have is, once I do a redirection to an external server, how do I get the post redirection code to execute ? The control will be totally out of my application right ?
All the 3 steps above happen on clicking a command button , and my code is under doPost()
Assuming that you're using standard Java EE stack, just put #Asynchronous on the EJB service method you're invoking after redirect. It'll run in a separate thread and allowing the current thread to continue directly (and thus to return from action method directly without blocking).
E.g.
#ManagedBean
#RequestScoped
public class Bean {
#EJB
private SomeService someService;
public void doPost() throws IOException { // Strange name for a JSF command button action btw, confuses with a standard HttpServlet method.
// ... Preprocessing ...
externalContext.redirect(externalURL);
someService.doSomethingAsynchronously();
}
// ...
}
with
#Stateless
public class SomeService {
#Asynchronous
public void doSomethingAsynchronously() {
// ... Update stuff ...
}
// ...
}

How can I initialize a Java FacesServlet

I need to run some code when the FacesServlet starts, but as FacesServlet is declared final I can not extend it and overwrite the init() method.
In particular, I want to write some data to the database during development and testing, after hibernate has dropped and created the datamodel.
Is there a way to configure Faces to run some method, e.g. in faces-config.xml?
Or is it best to create a singleton bean that does the initialization?
Use an eagerly initialized application scoped managed bean.
#ManagedBean(eager=true)
#ApplicationScoped
public class App {
#PostConstruct
public void startup() {
// ...
}
#PreDestroy
public void shutdown() {
// ...
}
}
(class and method names actually doesn't matter, it's free to your choice, it's all about the annotations)
This is guaranteed to be constructed after the startup of the FacesServlet, so the FacesContext will be available whenever necessary. This in contrary to the ServletContextListener as suggested by the other answer.
You could implement your own ServletContextListener that gets notified when the web application is started. Since it's a container managed you could inject resources there are do whatever you want to do. The other option is to create a #Singleton ejb with #Startup and do the work in it's #PostCreate method. Usually the ServletContextListener works fine, however if you have more than one web application inside an ear and they all share the same persistence context you may consider using a #Singleton bean.
Hey you may want to use some aspects here. Just set it to run before
void init(ServletConfig servletConfig)
//Acquire the factory instances we will
//this is from here
Maybe this will help you.

StackOverflow error when initializing JSF SessionScoped bean in HttpSessionListener

Continuing on my previous question, I'm trying to initialize a session-scoped JSF bean when the application's session first starts, so the bean will be available to a user, regardless of which page they access on my web application first. My custom listener:
public class MyHttpSessionListener implements HttpSessionListener {
#Override
public void sessionCreated(HttpSessionEvent se) {
if (FacesContext.getCurrentInstance().getExternalContext().getSessionMap()
.get("mySessionBean") == null) {
FacesContext.getCurrentInstance().getExternalContext().getSessionMap()
.put("mySessionBean", new MySessionBean());
}
}
}
However, this is giving me a stack overflow error. It appears that the put() method in the SessionMap class tries to create a new HttpSession, thus causing an infinite loop to occur with my listener. How can I initialize a JSF session-scoped bean when my application's session first starts, without running into this issue?
I'm using JSF 2 with Spring 3, running on WebSphere 7.
Thanks!
The session isn't been fully finished creating at that point. Only when the listener method leaves, the session is put into the context and available by request.getSession() as JSF's getSessionMap() is using under the covers.
Instead, you should be grabbing the session from the event argument and use its setAttribute() method. JSF lookups and stores session scoped managed beans just there and won't create a new one if already present.
public void sessionCreated(HttpSessionEvent event) {
event.getSession().setAttribute("mySessionBean", new MySessionBean());
}
Note that I removed the superfluous nullcheck as it's at that point impossible that the session bean is already there.
Unrelated to the concrete problem, you should actually never rely on the FacesContext being present in an implementation which isn't managed by JSF. It is quite possible that the session can be created during a non-JSF request.

Resources