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.
Related
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.
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.
All of the ExceptionHandlerFactory examples I have come across so far redirect a user to a viewExpired.jsf page in the event that a ViewExpiredException is caught:
public class ViewExpiredExceptionExceptionHandler extends ExceptionHandlerWrapper {
private ExceptionHandler wrapped;
public ViewExpiredExceptionExceptionHandler(ExceptionHandler wrapped) {
this.wrapped = wrapped;
}
#Override
public ExceptionHandler getWrapped() {
return this.wrapped;
}
#Override
public void handle() throws FacesException {
for (Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator(); i.hasNext();) {
ExceptionQueuedEvent event = i.next();
ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
Throwable t = context.getException();
if (t instanceof ViewExpiredException) {
ViewExpiredException vee = (ViewExpiredException) t;
FacesContext facesContext = FacesContext.getCurrentInstance();
Map<String, Object> requestMap = facesContext.getExternalContext().getRequestMap();
NavigationHandler navigationHandler = facesContext.getApplication().getNavigationHandler();
try {
// Push some useful stuff to the request scope for use in the page
requestMap.put("currentViewId", vee.getViewId());
navigationHandler.handleNavigation(facesContext, null, "/viewExpired");
facesContext.renderResponse();
} finally {
i.remove();
}
}
}
// At this point, the queue will not contain any ViewExpiredEvents. Therefore, let the parent handle them.
getWrapped().handle();
}
}
It seems to me that the following simple web.xml configuration is fundamentally the same and a lot simpler:
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/viewExpired.jsf</location>
</error-page>
This prompts the question - why would one use an ExceptionHandlerFactory?
The particular example does only one useful thing: it saves the view ID as a request attribute so that you can use for example
<h:link value="Go back to previous page" outcome="#{currentViewId}" />
But this is not tremendously useful as the raw request URI is already available by the <error-page>'s default request attribute javax.servlet.error.request_uri.
<h:outputLink value="#{requestScope['javax.servlet.error.request_uri']}">Go back to previous page</h:outputLink>
However one thing what a custom ExceptionHandler is really useful for is that it allows you to deal with exceptions during ajax requests. By default they have namely no single form of helpful feedback in the client side. Only in Mojarra with project stage set to "Development" you'll see a bare JavaScript alert message with the exception message. But that's it. There is no single form of feedback in "Production" stage. With a custom ExceptionHandler you would be able to parse the web.xml to find the error page locations, create a new UIViewRoot with it and force JSF to set ajax rendering to #all.
So, basically:
String errorPageLocation = "/WEB-INF/errorpages/500.xhtml";
context.setViewRoot(context.getApplication().getViewHandler().createView(context, errorPageLocation));
context.getPartialViewContext().setRenderAll(true);
context.renderResponse();
See also this related question: What is the correct way to deal with JSF 2.0 exceptions for AJAXified components? and this blog: Full Ajax Exception Handler.
It depends what do you want to do when you recive ViewExpiredException.
If you just want to display to a user error page you can do it like you said.
This post show you how to programmatically intercept the
ViewExpiredException and do something nice with it.
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);
}
Basically, I need to call a method after RENDER_RESPONSE phase. I tried this:
<f:phaseListener type="com.examples.MyPhaseListener"/>
The above listener is listenening all the time even for ajax calls. I tried
rendered="#{!facesContext.postback}"
but its not applicable here I guess. So I tried this as mentioned in this post Is it possible to disable f:event type="preRenderView" listener on postback?:
public void beforePhase(PhaseEvent pe) {
if (!FacesContext.getCurrentInstance().isPostback()) {
//do nothing
}
}
public void afterPhase(PhaseEvent pe) {
if (!FacesContext.getCurrentInstance().isPostback()) {
if (pe.getPhaseId() == PhaseId.RENDER_RESPONSE) {
//call a method
}
}
}
It is working but is there any other way to disable the listener after the initial response?
I also tried preRenderComponent but it is called in before RENDER_RESPONSE phase and it looks like it is not rendering response until the method is out of the stack ( basically it is not asynchronous). So I feel there is not much advantage of SystemEvents like preRenderView and preRenderComponent when compared to calling them in PostConstruct.
There's not really another way to achieve the functional requirement. A Filter wherein you do the job after the chain.doFilter(request, response) call should also work, but this doesn't give you access to the faces context (although a lot of JSF specific data is also available by the standard Servlet API).
As to your phase listener, if you need to get it to listen on render response only, then add
public PhaseId getPhaseId() {
return PhaseId.RENDER_RESPONSE;
}
This way you don't need to check the current phase in the listener methods.
public void afterPhase(PhaseEvent event) {
if (!FacesContext.getCurrentInstance().isPostback()) {
// ...
}
}
In the upcoming JSF 2.2 there will by the way be a new tag which understands isPostback(), the <f:viewAction>:
<f:viewAction action="#{bean.action}" onPostback="false" />
However, it runs during invoke action phase only.