0

We have a page that contains a command link:

<h:commandLink value="Go to Result Manager"
               action="#{resultManagerDashboardHelper.navigateToTargetAll()}" />

This is supposed to redirect to the Result Manager view, secretly passing a list of two status flags representing "TODO" and "DONE", so that the filter will be set to "all statuses".

ResultManagerDashboardHelper.java:

@Named
@ViewScoped
public class ResultManagerDashboardHelper
{
    ...

    public static final String SECRET_ARGS_KEY  = "secretArgs";

    ...

    private String navigateToPage( String outcome, String... args )
    {
        List<String> argsList = Arrays.asList( args );
        FacesContext.getCurrentInstance().getExternalContext().getFlash().put( SECRET_ARGS_KEY, argsList );

        String fullOutcome = outcome + "?faces-redirect=true";

        System.out.println( "Setting flash secret args to " + argsList );
        System.out.println( "Redirecting from '" + this.outcomeMapper.getCurrentOutcome() + "' to '" + fullOutcome + "'" );

        return fullOutcome;
    }

    private String navigateToTargetPage( String... args )
    {
        return this.navigateToPage( "/view/resultmgmt/resultManager", args );
    }

    public String navigateToTargetAll()
    {
        return this.navigateToTargetPage( "TODO", "DONE" );
    }
}

ResultManagerFilterHandler.java:

@Named
@ViewScoped
public class ResultManagerFilterHandler
{
    ...

    // status flags secretly coming in via Flash from dashboard
    private List<String> secretStatusFlags;

    @Override
    @PostConstruct
    public void init()
    {
        ...

        @SuppressWarnings( "unchecked" )
        List<String> secretStatusFlags = ( List<String> ) FacesContext.getCurrentInstance().getExternalContext().getFlash().get( ResultManagerDashboardHelper.SECRET_ARGS_KEY );

        if ( secretStatusFlags != null )
        {
            System.out.println( "ResultManagerFilterHandler secret arguments have arrived via JSF Flash! Size = " + secretStatusFlags.size() );
        }
        else
        {
            System.out.println( "ResultManagerFilterHandler: NO secret arguments have arrived via JSF Flash!" );
        }

        // sits in view scope waiting to be picked up by search routine in ResultManager (also view-scoped)
        this.secretStatusFlags = secretStatusFlags;
    }
}

ResultManager.java:

@Named
@ViewScoped
public class ResultManager
{
    ...

    @Inject
    private ResultManagerFilterHandler filterHandler;

    @Override
    public void searchInitially()
    {
        // get Flash object from filter handler
        List<String> statusFlags = this.getFilterHandler().getSecretStatusFlags();

        System.out.println( "ResultManager statusFlags = " + statusFlags );

        // if flash args have been passed, prefer that view over the standard one
        if ( statusFlags != null && !statusFlags.isEmpty() )
        {
            System.out.println( "Flash search!" );

            // set to today and decrypt the passed status flags (this is supposed to override the default search filter!)
            this.filterHandler.setSelectedPeriod( EPeriod.TODAY );
            this.filterHandler.calculateBeginEndDates( this.filterHandler.getSelectedPeriod() );
            this.filterHandler.setTodoOnly( statusFlags.size() == 1 && statusFlags.get( 0 ).equals( "TODO" ) );

            this.search();
        }
        else
        {
            System.out.println( "Non-flash search!" );

            super.searchInitially();
        }
    }
}

When clicking the aforementioned link, the browser is redirected to the correct view. Then an event on the resultManager.xhtml page

<f:event type="preRenderView"
         listener="#{resultManager.searchInitially}" />

calls the searchInitially method, which is supposed to pick up the stored status flags from the ResultManagerFilterHandler bean. However the Flash arguments aren't there:

18:58:42,840 INFO    [] (134) Setting flash secret args to [TODO, DONE]
18:58:42,840 INFO    [] (134) Redirecting from '/view/dashboard' to '/view/resultmgmt/resultManager?faces-redirect=true'
18:58:43,039 INFO    [] (135) ResultManagerFilterHandler: NO secret arguments have arrived via JSF Flash!
18:58:44,350 INFO    [] (135) ResultManager statusFlags = []
18:58:44,350 INFO    [] (135) Non-flash search!

Q:

What am I doing wrong? How do I get it to work?

Note that ?faces-redirect=true URL parameter isn't appended to the URL... I wonder why?? Might this be the reason for the empty flash? Or is it normal behavior?


We're using Mojarra 2.1.22, which is known to have some issues keeping Flash instances longer, but this is something I'd like to solve later.

PS: sorry for the complex example, in reality it is even more complex... :-/

PPS: oh and never mind the combination of @Named and @ViewScoped, we're using Seam 3, which replaces the JSF @ViewScoped with a CDI-compatible one.

Aritz
  • 30,971
  • 16
  • 136
  • 217
Kawu
  • 13,647
  • 34
  • 123
  • 195

1 Answers1

0

First of all, I encourage you not to use two @ViewScoped beans for the same view. You can achieve this functionality either carrying the functionallity of ResultManagerFilterHandler to your ResultManager. If you however want to reuse ResultManagerFilterHandler methods in other beans, just use a plain class (not managed by JSF) and make your managed beans extend from it.

On the other hand, there's no point for using 2.1.22 anymore. Just go with latest 2.1.x branch version, it'll be fully compatible with the code you have and brings lots of bug fixes, specially the ones related with flash scope.

Related with faces-redirect="true", keep in mind the Faces Servlet processes your redirection url before sending it to the browser. This parameter only tells that you want to perform a redirection, the servlet will remove it after evaluating.

See also:

Community
  • 1
  • 1
Aritz
  • 30,971
  • 16
  • 136
  • 217