Liferay Portlet and JSF : Redirect during Render Phase
Asked Answered
I

3

5

I have a problem to implement a simple HTTP redirection.

I use Liferay 6.0.6, our portlets are build with JSF2.0 / PortletFaces.

I want to call a redirection when a view is loaded (and not when an action is triggered). Currently, my function is called by the PreRenderView listener.

<f:metadata>
  <f:event listener="#{myControler.dispatch}" type="preRenderView" />
</f:metadata>

In this function, i can check the permissions, do other stuff, and in some cases I want to redirect the user to a new page (not another view).

I tried several methods, unsuccessfully. Specifically, I thought that this method would work :

getFacesContext().getExternalContext().redirect(url);
getFacesContext().responseComplete()
// => Can only redirect during ACTION_PHASE

This error is logical, but is there a solution to force the redirection.

It could be realized in another function, called otherwise, I only need the Hibernate Session (set at the beginning of the Render Phase)

Have you ideas to resolve this problem?
Thanks!

ps : <redirect /> or ?faces-redirect don't work with the portlets.

Inexpiable answered 29/7, 2011 at 20:44 Comment(0)
L
10

You can't do this in the render phase by design. Reasons:

  • It's possible that portlets are rendered asynchronously, so the page might already be displayed when your portlet is being rendered
  • It's possible that parts of the page are already delivered to the client, so that the HTTP Headers are already sent - for this reason, by design you don't have access to them in the render phase
  • What would be the expected outcome if two portlets rendered on the same page would decide that they'd like to forwards to another page? Who would win?

A hacky workaround is to render some javascript redirect, but this is veeeery un-portal-like and can mess up other's expectations (plus, parts of the page might already be rendered, causing your users to fill a form only to be redirected by your javascript routine.

Please rethink the problem and come up with a different solution - it's really worth doing this in a portal environment.

Limp answered 30/7, 2011 at 9:8 Comment(5)
Thank you for your explanation. I will think to another solution, and refactor my portlet architecture if necessary.Inexpiable
Another hacky workaround is to use the PortalUtil.getHttpServletResponse to find the original HTTP request and use sendRedirect there.Unassuming
@TobiasLiefke too hacky IMHO - the response might already be committed during render time. Or the portlet might be delivered through Ajax, not even as part of the whole page. It might work, but it also might work now and break at some future update of the appserver...Limp
It's not the appserver, but the portal which could break that in future versions - the appserver won't commit the response by itself.Unassuming
I've seen differences on the same appserver on different operating systems - the buffering might not be dependent on either appserver or portal, but on other factors that we didn't even discuss. Anyway, if I'd be able to predict where the problems will be, they could be worked around now. But I can't predict this, thus what I'm trying to do is to point at the possibility of breakage. It might be the portal, yes, but it might be anything else. Enter dynamic loading of individual portlets through Ajax and you can't even expect it to work today. Do not assume you're loading the full page!Limp
J
1

I use this and it works for me:

    public void preRenderView() throws IOException {

        if (!checkUtente()) {  

              FacesContext fc = FacesContext.getCurrentInstance(); 

              NavigationHandler navigationHandler = fc.getApplication().getNavigationHandler();

              navigationHandler.handleNavigation(fc, null, "errore.xhtml?faces-redirect=true");

              fc.renderResponse(); 
        }

    }
Janejanean answered 25/4, 2015 at 8:55 Comment(0)
A
0

Use the below method it will work

public static void redirect(final String url) throws IOException {

            final javax.portlet.PortletResponse portletResponse
            = getPortletResponse();

            if (portletResponse instanceof ActionResponse) {

                final javax.portlet.ActionResponse actionResponse
                = (javax.portlet.ActionResponse) portletResponse;

                actionResponse.sendRedirect(url);

            } else if (portletResponse instanceof ResourceResponse) {

                final FacesContext ctx = FacesContext.getCurrentInstance();
                if (ctx.getPartialViewContext().isPartialRequest()) {

                    final ResourceResponse portletResResp
                    = (ResourceResponse) portletResponse;
                    PartialResponseWriter pwriter;
                    final ResponseWriter writer = ctx.getResponseWriter();
                    if (writer instanceof PartialResponseWriter) {
                        pwriter = (PartialResponseWriter) writer;
                    } else {
                        pwriter = ctx.getPartialViewContext()
                        .getPartialResponseWriter();
                    }
                    portletResResp.setContentType(Constants.CONTENT_TYPE);
                    portletResResp.setCharacterEncoding(Constants.ENCODING_TYPE);
                    // addResponseHeader("Cache-Control", "no-cache");
                    pwriter.startDocument();
                    pwriter.redirect(url);
                    pwriter.endDocument();
                    ctx.responseComplete();
                } else {
                    throw new UnsupportedEncodingException(
                            "Can only redirect during RESOURCE_PHASE "
                            + "if a Partial-(JSF AJAX)-Request  has "
                            + "been triggered");
                }
            } else {
                throw new UnsupportedEncodingException(
                        "Can not redirect during the current phase: "
                        + portletResponse.getClass().getSimpleName());
            }
        }
Albite answered 11/8, 2011 at 13:59 Comment(1)
Sorry but it will not work, because i want to redirect during a RenderPhase (with portletResponse istanceof RenderResponse). So i will get a "Can not redirect during the current phase"Inexpiable

© 2022 - 2024 — McMap. All rights reserved.