Open p:dialog when asynchronous task is completed - jsf

I need a technique in which I can call java method for retrieving information from DB and displaying message in dialog box and by pressing "Next" button, if have any next message it will appear. That java method calls automatically after a specific time, says first time when user logged-in and then after ever 3 min. This I want in JSF & PrimeFaces.
I used ScheduleExecutarService for scheduling and my run method as below
public void run() {
try {
System.out.println("beep");
notificationList = retrieveNotificationsFromDB(userId, groupCode, functionCode, chooseNotificationType());
if(notificationList != null && !notificationList.isEmpty()){
showPopup();
}
} catch(Exception e) {
LOGGER.error(e.getMessage());
}
}
public void showPopup() {
if (notificationList != null && !notificationList.isEmpty()) {
setNotificatiomMessage(notificationList.get(0).getMessage());
notificationList.remove(0);
RequestContext.getCurrentInstance().execute("PF('dialogVar').show()");
}
}
In showPopup() I'm not able to get the object of RequestContext
Other Way I tried <p:poll> tag, I read that about the tag is there is a problem for stopping it.
Please guide me what I should use.

In showPopup() I'm not able to get the object of RequestContext
Because there is no active HTTP request (from the client to the server) which is handled at this point.
Solution:
Let the Scheduler fire a CDI event and catch this event with a CDI observer in your client bean.
Now you have to options: Either let the JSF view poll your client bean to ask for new messages, or you create a socket, over which the client bean may inform the JSF view about new messages. You are able to handle the incoming message on your JSF view via JavaScript and do with it whatever you want.
For a very basic example for sockets, see here:
http://www.primefaces.org/showcase/push/counter.xhtml
See also:
https://docs.oracle.com/javaee/6/tutorial/doc/gkhic.html

Finally I got the simple solution with these 2 line of code
<p:poll id="initNotificationAlert" interval="1" oncomplete="PF('initNotificationVar').stop()" listener="#{notificationView.retrieveAlertNotification()}" widgetVar="initNotificationVar"></p:poll>
<p:poll id="notificationAlert" autoStart="false" interval="180" listener="#{notificationView.retrieveAlertNotification()}" widgetVar="notificationVar"></p:poll>
first <p:pol> for initial message and second for <p:pol> for rest.
if any better solution of improvement need in this solution improve it.
Thanks

You can open dialog manually like this:
Scheduler
There are many schdulers like Quartz or for WebApplication
Dialog
public String showDialog(String dialogName){
Map<String, Object> options = new HashMap<String, Object>();
options.put("modal", true);
options.put("closable", true);
options.put("draggable", true);
options.put("resizable", true);
options.put("contentHeight", 386);
options.put("contentWidth", 1266);
RequestContext.getCurrentInstance().openDialog(dialogName, options, null);
return "";
}
While dialogName is that .xhtml page you are trying to show. You just need a schedular to call this method and dialog will appears.

Related

FullAjaxExceptionHandler - Find out which component caused ViewExpiredException?

Is it possible to tell which component was clicked that caused the ViewExpiredException to be thrown when using AJAX? I'd like to avoid showing the session expired page if the user simply tried to log out and show him the normal log out page instead.
I was thinking of overriding shouldHandleExceptionRootCause but I cannot find anything to identify if the logout button was pressed or not.
I'm using Mojarra JSF 2.2 and Omnifaces 2.5.1.
Solution
#Override
protected boolean shouldHandleExceptionRootCause(FacesContext context, Throwable exception)
{
UIComponent source = Components.getCurrentActionSource();
if (source != null && "logout".equals(source.getId()))
{
NavigationHandler nh = context.getApplication().getNavigationHandler();
nh.handleNavigation(context, null, "logout.xhtml?faces-redirect=true");
return false;
}
else
{
return super.shouldHandleExceptionRootCause(context, exception);
}
}
The Components utility class offers several methods to identify the currently submitted form, the currently invoked command and the source component of the action event (which can be the command component itself, but also an input component in case of an ajax event).
UIForm form = Components.getCurrentForm();
UICommand command = Components.getCurrentCommand();
UIComponent source = Components.getCurrentActionSource();
Take your pick. You could for example check the id of the form, command or source to see if it's the desired one.

How to update (redirect in) the main window from a method in a managed bean triggered from another window?

I have a main window (window1), a second window (window2) which was opened by window.open() from a managed bean and a managed bean (controller).
window2 triggers a method in the controller. If a specific condition is true, controller should close window2 and change the page from /test/page1.xhtml to /test/page2.xhtml in window1.
The method in the controller looks like that:
String result = model.doSomething();
if (result.matches("[0-9]+")) {
RequestContext.getCurrentInstance().execute("window.close()");
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
try {
FacesContext.getCurrentInstance().getExternalContext().redirect(request.getContextPath() + "/test/page1.xhtml");
} catch (IOException e) {
MessageHelper.showMessage(null, e.getMessage(), FacesMessage.SEVERITY_ERROR, this);
}
}
The problem is the line HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest(); I guess.
I have no idea how to command window1 to change the page from controller immediately after closing window2.
The solution has to work under IE 11.
I'm using Primefaces 5.2 and JSF 2.0.
This can simply be done using JavaScript. Just add window.opener.document.location = '{yourlocation}'; before window.close(). So:
RequestContext.getCurrentInstance().execute(
"window.opener.document.location = '"+ request.getContextPath() +"/test/page1.xhtml';"+
"window.close()"
);
See also:
When to use window.opener / window.parent / window.top

How to programatically open a dialog box in primefaces without user click?

I am working on an exam management session using Java EE 7 and Primefaces. Tests are timed and once the time is over, I want to display a dialog box automatically(i.e. without user clicking any button). I successfully used Primefaces Dialog framework on the click of a button, but can't do it automatically.
For timing the test I am using TimerService, which calls a stateless EJB's method on timeout. I have a session scoped CDI bean which creates the timer.
This is the post construct method of the CDI bean.
public void init() {
studentAnswers = new ArrayList<StudentAnswer>();
examSections=ePaper.getSections();
examTimerBean.createExamPaperDuration(10,RequestContext.getCurrentInstance());
}
The stateless EJB is as follows -
#Stateless
public class ExamTimerBean {
#Resource TimerService timerService;
RequestContext reqCtx;
public void createExamPaperDuration(int duration,RequestContext reqCtx){
this.reqCtx=reqCtx;
timerService.createTimer(duration*1000, null);
}
#Timeout
public void examTimeExpired(){// throws IOException{
try{
reqCtx.openDialog("thanks");
}
catch(EJBException e){
System.out.println(e.getMessage());
}
}
}
I am passing the request context to the EJB, but the dialogBox doesn't open. Kindly help.

ActionResponse object for Jsf bean action

When I click on submit button for a jsf page from a jsf portlet, mymethod of jsf bean is invoked.
<h:commandButton id="id1" action="#{Mybean.mymethod}" value="Click" />
public String mymethod() {
FacesContext fc = FacesContext.getCurrentInstance();
Object obj = fc.getExternalContext().getResponse();
if (obj instanceof ActionResponse){
System.out.println("ActionResponse !");
} else if (obj instanceof RenderResponse) {
System.out.println("RenderResponse !");
}
}
But none of the types its satisfying for Response object. What type of response is it?
Beause I am trying to figure if it is ActionResponse, then I need to set setEvent method.
And I guess it should be ActionResponse type right? I wonder why its not.
<-Modified->
Now I am getting Action Response. Might be because I have jsf 1.2 instead of 1.1 and I am in different system.
For a Portlet A, I have set the event in bean as follows,
ar.setEvent("showResults", "true"); //ar is ActionResponse
Then in Portlet class for Portlet B, I am doing as follows,
public class IPC extends GenericFacesPortlet {
protected void doView(RenderRequest request, RenderResponse response)
throws PortletException, IOException
{
if (request.getAttribute("showResults") == "true") {
request.setAttribute("javax.portlet.faces.viewId", "/JsfB_alt.jsp");
}
super.doView(request, response);
}
#ProcessEvent
public void processIPCEvent(EventRequest eRequest, EventResponse eResponse)
throws PortletException, IOException
{
Event event = eRequest.getEvent();
if(event.getName().equals("showResults")){
System.out.println("Event encountered !");
eRequest.setAttribute("showResults", "true");
}
}
}
So what I am trying to do is change from default view of Portlet B from /JsfB.jsp to /JsfB_alt.jsp when I click the button in Portlet A by setting an event.
But event is not listened as I can see that "Event encountered" is not getting printed.
I even tried changing processIPCEvent to processEvent with #Override but still its not called. I hope it will be called automatically when there is any event, right?
I feel problem in setting event in ar.setEvent()
What do you think?
FYI, I am using weblogic server 10.3 and jsf 1.2
Please suggest what could be the problem.
This is probably due to the portlet bridge implementation being used in your application.
Since the JSF implementations are written to work with the servlet API, they won't work out of the box in a portlet. So, when a context is created the portlet response will likely be adapted to a servlet response. The context merely returns the objects passed to it at creation time.
In the bridges I've used (IBM implementations) these wrappers also implement the portlet interfaces but I'm not aware of a requirement to do so.
You may want to state your platform, libraries and their versions if you want a more informed answer.
I defined as java event (jsr) using <event-definition> and <supported-processing-event> in portlet.xml and now I am able to listen to it.

Adding faces message to redirected page using ExternalContext.redirect()

I am using ExternalContext.redirect(String); method to redirect user to another page:
FacesContext.getCurrentInstance().addMessage(new FacesMessage("Bla bla bla..."));
FacesContext.getCurrentInstance().getExternalContext().getFlash().setKeepMessages(true);
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.redirect(ec.getRequestContextPath() + "/scenario.xhtml");
As Matt Handy mentioned in his answer, I used Flash.setKeepMessages(true); but it does not seem to work with ExternalContext.redirect. (Although it works when I redirect by returning a page name from bean's action method.)
Now how can I add FacesMessage so that it is visible in the redirected (scenario.xhtml) page?
This seems to be a timing problem. This listener method is invoked during the preRenderView event. According to the source code of ELFlash (Mojarra's Flash implementation as returned by ExternalContext#getFlash()) it turns out that it won't set the flash cookie when you're currently sitting in the render response phase and the flash cookie hasn't been set yet for the current request:
Here are the relevant lines from ELFlash:
if (currentPhase.getOrdinal() < PhaseId.RENDER_RESPONSE.getOrdinal()) {
flashInfo = flashManager.getPreviousRequestFlashInfo();
} else {
flashInfo = flashManager.getNextRequestFlashInfo(this, true);
maybeWriteCookie(context, flashManager);
}
The maybeWriteCookie would only set the cookie when the flash cookie needs to be passed through for the second time (i.e. when the redirected page in turn redirects to another page).
This is an unfortunate corner case. This ELFlash logic makes sense, but this isn't what you actually want. Basically you need to add the message during INVOKE_APPLICATION phase instead. There is however no such event as postInvokeAction. With the new JSF 2.2 <f:viewAction> tag it should be possible as it really runs during invoke application phase.
<f:viewAction action="#{bean.onload}" />
As long as you're not on JSF 2.2 yet, you'd need to look for alternate ways. The easiest way would be to create a custom ComponentSystemEvent.
#NamedEvent(shortName="postInvokeAction")
public class PostInvokeActionEvent extends ComponentSystemEvent {
public PostInvokeActionEvent(UIComponent component) {
super(component);
}
}
Now you need somewhere a hook to publish this event. The most sensible place is a PhaseListener listening on after phase of INVOKE_APPLICATION.
public class PostInvokeActionListener implements PhaseListener {
#Override
public PhaseId getPhaseId() {
return PhaseId.INVOKE_APPLICATION;
}
#Override
public void beforePhase(PhaseEvent event) {
// NOOP.
}
#Override
public void afterPhase(PhaseEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
context.getApplication().publishEvent(context, PostInvokeActionEvent.class, context.getViewRoot());
}
}
If you register it as follows in faces-config.xml
<lifecycle>
<phase-listener>com.example.PostInvokeActionListener</phase-listener>
</lifecycle>
then you'll be able to use the new event as follows
<f:event type="postInvokeAction" listener="#{bean.onload}" />
Update this is also available in the JSF utility library OmniFaces, so you don't need to homebrew the one and other. See also the InvokeActionEventListener showcase example.
Use the flash to keep messages over a redirect.
Add these two lines to your code before redirecting:
FacesContext context = FacesContext.getCurrentInstance();
context.getExternalContext().getFlash().setKeepMessages(true);
Note that the there are some issues with Mojarra's flash scope implementation. Keep this in mind if you use it.
Using Matt Handy's example as a reference, I created the method below that worked very well for me.
public static void Message(String message) {
FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_INFO, mensagem, null);
FacesContext context = FacesContext.getCurrentInstance();
context.getExternalContext().getFlash().setKeepMessages(true);
context.addMessage(null, fm);
}

Resources