-
1. Re: Reset View Id
uwew Jun 3, 2013 10:32 AM (in response to uwew)After trying around and having a look at the JSR-301 specs i came around the following:
Chapter 3.4. says:
In addition to the incoming information in the portlet request, the portlet provides additional bridge request context by setting attributes in the request using PortletRequest.setAttribute(). To direct the bridge to execute a specific Faces target the portlet can set either of the following before calling doFacesRequest:
javax.portlet.faces.viewId: The value of this attribute identifies the Faces viewId the bridge must use for this request (e.g. /myFacesPage.jsp). This is expected to be a valid Faces viewId though it may optionally contain a query string.
javax.portlet.faces.viewPath: The value of this attribute contains the the Faces viewId the bridge must use for this request in ContextPath relative path form (e.g. /faces/myFacesPage.jsp). This value may optionally contain a query string.
So my question is: is this implemented in the Jboss Portlet Bridge, and, if yes, how can i use it? I already tried to set these request parameters in a portlet filter, but with no success. Still the bridge is redirecting ot a differnet view, other than set in javax.portlet.faces.viewId.
Any help is appreciated!
Kind Regards,
Uwe
-
2. Re: Reset View Id
kenfinni Jun 3, 2013 10:54 AM (in response to uwew)From looking at the code of GenericFacesPortlet, as provided by the spec, javax.portlet.faces.viewId is set by this class based on a different value, hence why setting it in a Filter is not working.
What you can try setting in the filter is a request parameter value for _jsfBridgeViewId, as this is the value that is fed into viewId for the Portlet Bridge.
-
3. Re: Reset View Id
uwew Jun 3, 2013 11:00 AM (in response to kenfinni)i also tried to use _jsfBridgeViewId as a request parameter, unfortunately this parameter gets overriden by the bridge, so that in the render phase the parameter is set with a wrong value.
Unfortunately i cannot set the parameter in the action phase programmatically, as i am not able to invoke the action phase via the url. Urls (links) remain in a separate navigation portlet and i am unable to determine the corresponding containerId for each link.
Kind Regards,
Uwe
-
4. Re: Re: Reset View Id
laszlovandenhoek Jan 24, 2014 8:58 AM (in response to uwew)@uwew:
did you eventually find a solution to this problem?
We did have a workaround that worked with portal bridge 2.1.0; we extend GenericFacesServlet with the following, passing the resetPortlet attribute in the URL:
import java.io.IOException;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.faces.GenericFacesPortlet;
import org.apache.commons.lang.StringUtils;
import org.exoplatform.portal.webui.util.Util;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.jboss.portletbridge.BridgeRequestScope;
import org.jboss.portletbridge.RequestScopeManager;
import org.jboss.portletbridge.StateId;
/**
* Generic portlet that supports resetting portlets to an default JSF outcome.
*/
public class GenericJsfPortlet extends GenericFacesPortlet {
/** (Request) attribute for resetting the portlet. */
public static final String ATTR_RESET_PORTLET = "outcomeForReset";
/** Logger. */
private static final Log log = ExoLogger.getLogger(GenericJsfPortlet.class);
/** HTTP GET parameter for resetting portlets. */
private static final String HTTP_PARAM_RESET_PORTLET = "resetPortlet";
/**
* {@inheritDoc}
*/
@Override
public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException {
// Detect reset.
String value = Util.getPortalRequestContext().getRequestParameter(HTTP_PARAM_RESET_PORTLET);
log.debug(String.format("%1s = %2s", HTTP_PARAM_RESET_PORTLET, value));
if (!StringUtils.isEmpty(value) && Boolean.valueOf(value)) {
// Does the portlet support the reset?
String outcome = getInitParameter(ATTR_RESET_PORTLET);
log.debug(String.format("[%1s]%2s = %3s", getPortletName(), ATTR_RESET_PORTLET, outcome));
if (!StringUtils.isEmpty(outcome)) {
// We're using JSF here, so let Faces do the dispatching.
log.debug(String.format("Reset detected: Set JSF outcome '%1s' for portlet '%2s'", outcome, getPortletName()));
request.setAttribute(ATTR_RESET_PORTLET, outcome);
// If there are any faces messages hanging around, remove them.
log.debug(String.format("Reset detected: Reset Bridge Scope"));
RequestScopeManager requestStateManager = RequestScopeManager.getInstance(request,RequestScopeManager.DEFAULT_MAX_MANAGED_SCOPES);
StateId stateId = requestStateManager.getStateId(request, response);
requestStateManager.saveRequestScope(stateId, new BridgeRequestScope());
}
}
// Delegate to faces portlet for navigation and rendering.
super.doView(request, response);
}
}
...but when I upgrade to portal bridge 3.2.1 as part of our migration to JBoss Portal Platform 6.1, the RequestScopeManager import breaks.
@Ken Finnigan: any idea how we can convert this code to work with the latest Portlet Bridge version?
-
5. Re: Re: Reset View Id
kenfinni Jan 24, 2014 9:57 AM (in response to laszlovandenhoek)From your extended GenericFacesPortlet you should be able to do something like:
BridgeContext.getCurrentInstance().getBridgeRequestScopeManager().removeRequestScopesByPortlet(BridgeContext.getCurrentInstance());
This essentially removes all saved scopes for the current portlet.
This isn't something I've tried, so it may also be necessary to remove request parameters to trigger the default faces view to be displayed.
-
6. Re: Re: Reset View Id
laszlovandenhoek Jan 24, 2014 5:08 PM (in response to kenfinni)Ken, thanks. I will give that a try and report back.
-
7. Re: Re: Reset View Id
uwew Jan 27, 2014 2:37 AM (in response to laszlovandenhoek)When using Portlet Bridge 2 we had a similar solution as mentiod above to reset the view id, which we put in a PortletFilter. Unfortunately this solution no longer works with the latest Bridge version.
I also tried the solution mentioned by Ken in a Filter and in a GenericJsfPortlet but in both ways the BridgeContext.getCurrentInstance always returns null. I don't know if i'm missing something or something has to be initialized prior to this.
What we did as another solution was a simple client based workaround. In an xhtml template we put the following code:
<pbr:actionURL var="actionUrl" portletMode="view">
<pbr:param name="_jsfBridgeViewId" value="/index.xhtml" />
</pbr:actionURL>
this is generating an ActionURL which points to the starting/init page.
After that, we replace all URLs in the page (which also incudes URLs in the MetaNavigation area, Navigation area,...) with the ActionURL:
<script>
var url = "<h:outputText value="${actionUrl}" />";
var searchUrl = url.substring(0, url.indexOf("?"));
searchUrl = searchUrl + "?initPortlet=1";
$( document ).ready(function() {
$("a[href*='" + searchUrl +"']")
.each(function()
{
this.href = this.href.replace(this.href, url);
});
});
</script>
As we don't want all URLs to be replaced, we have a marker (initPortlet=1) that determines an URL to replace.
If you include the above in all pages of your webapp (<ui:include src="/template/init.xhtml" />) then you will always be able to navigate to the initial page, regardless if you navigate within the webapp or navigate to the webapp from an external link.
Please let me know what you think about that or if you have found a smoother solution.
Kind Regards,
Uwe
-
8. Re: Re: Reset View Id
laszlovandenhoek Jan 27, 2014 5:14 AM (in response to uwew)Hi Uwe,
I can confirm that BridgeContext.getCurrentInstance() always returns null for me too. I agree that some initialization seems to be missing. I hope Ken can shed some light on this... I removed these two lines from faces-config.xml as suggested elsewhere:
<view-handler>org.jboss.portletbridge.application.PortletViewHandler</view-handler>
<state-manager>org.jboss.portletbridge.application.PortletStateManager</state-manager>
...but perhaps I need to add something similar to get BridgeContext.getCurrentInstance() to work?
As for your own solution: that would work to reset the view, but will it also remove any intermediate state that the portlet holds, such as partially entered form data? It would appear not.
Regards,
László
-
9. Re: Re: Reset View Id
kenfinni Jan 27, 2014 2:58 PM (in response to uwew)Apologies to you both, upon looking at it further the BridgeContext instance is nullified at the end of the Portlet Bridge request, so it is not available either in a filter or by extending GenericFacesPortlet.
Laszlo, are you also looking to access the default outcome from outside the portlet, or from inside it? If its only inside, you should be able to use h:link with the page name as the outcome.
-
10. Re: Re: Reset View Id
laszlovandenhoek Jan 29, 2014 5:51 AM (in response to kenfinni)Hi Ken,
pretty much only from outside the portlet, really. From within the portlet itself, we have navigational buttons between the views, but when users are arriving from an external link or a bookmarked URL, for example, we expect them to see the same (initial) view every time, regardless of any previous activity within that portlet during their session.
I have found something that may be of interest: the BridgeContext may be inaccessible from a Filter or a GenericFacesPortlet, but it IS available from a PhaseListener. What I did not realize when I originally posted, is that our portal bridge 2.1.0 solution had two parts, the Portlet and a PhaseListener that did the actual navigating to the correct outcome. Naïvely sticking the removeRequestScopesByPortlet call in the PhaseListener did not have the expected result, however; it may have something to do with the PhaseListener being declared for the RENDER_RESPONSE phase. I'll try some earlier phase and see if it makes a difference. Meanwhile, any feedback is appreciated.
Thanks,
László
-
11. Re: Re: Reset View Id
laszlovandenhoek Jan 29, 2014 7:36 AM (in response to laszlovandenhoek)Alright, changing the phase did not help, but putting the removeRequestScopesByPortlet call before the handleNavigation call instead of behind it did help somewhat. However, it doesn't work flawlessly; occasionally I get unpredicted view resets, as well as NullPointerExceptions
at javax.faces.component.UIComponent.popComponentFromEL(UIComponent.java:1936) [jboss-jsf-api_2.1_spec-2.1.19.1.Final-redhat-1.jar:2.1.19.1.Final-redhat-1]
at javax.faces.component.UIComponentBase.processSaveState(UIComponentBase.java:1292) [jboss-jsf-api_2.1_spec-2.1.19.1.Final-redhat-1.jar:2.1.19.1.Final-redhat-1]
at com.sun.faces.application.view.JspStateManagementStrategy.saveView(JspStateManagementStrategy.java:300) [jsf-impl-2.1.19-redhat-1.jar:2.1.19-redhat-1]
at com.sun.faces.application.StateManagerImpl.saveView(StateManagerImpl.java:92) [jsf-impl-2.1.19-redhat-1.jar:2.1.19-redhat-1]
at org.jboss.portletbridge.application.view.PortletJspVdlImpl$StringBuilderWriter.flushToWriter(PortletJspVdlImpl.java:265)
at org.jboss.portletbridge.application.view.PortletJspVdlImpl.renderView(PortletJspVdlImpl.java:165)
at org.jboss.portletbridge.application.PortletViewHandler.doRenderView(PortletViewHandler.java:251)
at org.jboss.portletbridge.application.PortletViewHandler.renderView(PortletViewHandler.java:245)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:120) [jsf-impl-2.1.19-redhat-1.jar:2.1.19-redhat-1]
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) [jsf-impl-2.1.19-redhat-1.jar:2.1.19-redhat-1]
I would love to dig further into this, but I've gotten a reply to my inquiry with Red Hat support (case 01018498), and they pointed me to this KB article:
https://access.redhat.com/site/solutions/547423
...which in turn points to Martin Weiler's alternative approach to solving the original problem, i.e. using a public render parameter that indicated whether the navigation changed (i.e. intra-portlet navigation) or not (i.e. coming from an external URL):
https://github.com/martinweiler/CustomProviderPlugin
That is not a complete solution to the problem, though, just a setup. I will try strategically mixing in the removeRequestScopesByPortlet call in the BridgePublicRenderParameterHandler - I guess that's the right place to call it.
Still interested in your thoughts!
László
-
12. Re: Reset View Id
uwew Jan 29, 2014 8:27 AM (in response to laszlovandenhoek)Some additional thoughts to my approach above: Laszlo, as you mentioned, it would reset the view id, but not the intermediate data.
As you can see, the generated URL is an ActionURL, so if you click the URL, the Request would first be redirected to the processAction of the GenericJsfPortlet. There you are able to invalidate the Portlet Session - i gave this a try and in my scenario if the Action URL is called the application jumps to the init page of the portlet (init.xhtml) and furthermore previously entered data in subsequent pages is no longer visible.
-
13. Re: Reset View Id
kenfinni Jan 29, 2014 9:58 AM (in response to laszlovandenhoek)László,
What version of Portlet Bridge are you using? If you're using 3.3.1.Final it should, by default, no longer retain scope information post RENDER for a JSF portlet. Which would mean navigating away from the portlet and then back again would give a portlet render as if you had never been there.
Ken
-
14. Re: Re: Reset View Id
laszlovandenhoek Jan 29, 2014 10:51 AM (in response to uwew)Uwe, invalidating the Portlet session does clear the internal Portlet state, but NOT the view. By the way, I have tried removing all state-resetting features and I still ran into the NullPointerException I mentioned earlier, so I think my basic setup needs some reviewing. It's pretty funky anyway, using JSP as a view technology and all...
Ken: I guess I'm stuck with 3.2.1.Final-redhat-4, as I am on JBoss Portal Platform 6.1. Or can I package a new version in my WAR and have my Portlets use that over the server-provided one?