Details

      Description

      One of the system event candidates that was overlooked in JSF 2.0 was a before navigation event, which would get fired just before the call to NavigationHandler#handleNavigation(). This is a very interesting transition and would open up a lot of possibilities for application developers, because JSF really don't accommodate this extension well. (Seam 2 had some functionality for setting context variables before navigation, but IMHO it would be far more powerful if we just raised an event so that the developer could execute any sort of logic before navigation).

      Forget even making a JSF system event out of it. Let's just raise it using CDI events (since we are bridging the JSF events anyway).

      I propose that we introduce the event qualifier:

      @Qualifier
      @Target(

      { FIELD, PARAMETER }

      )
      @Retention(RUNTIME)
      public @interface FacesNavigation {
      }

      and the event object would be the NavigationCase.

      public void preNavigate(@Observes @Before @FacesNavigation NavigationCase nc)

      { nc.getParameters().put("foo", Arrays.asList("bar")); }

      This can be combined with @Before and @View for filtering the event. We may even want @ToView to filter both the current and target view. Not sure how fine-grained to get.

      Here's a rough sketch of how this might be implemented. Unfortunately, this exposes the nastiness of the ConfigurableNavigationHandler in JSF 2.0, but at least we can leverage the NavigationCase resolution method we added for ourselves.

      public class SeamNavigationHandler extends ConfigurableNavigationHandler {

      private final NavigationHandler delegate;

      public SeamNavigationHandler(NavigationHandler delegate)

      { this.delegate = delegate; }

      @Override
      public NavigationCase getNavigationCase(FacesContext context, String fromAction, String outcome)
      {
      if (delegate instanceof ConfigurableNavigationHandler)

      { return ((ConfigurableNavigationHandler) delegate).getNavigationCase(context, fromAction, outcome); }

      // I guess
      return null;
      }

      @Override
      public Map<String, Set<NavigationCase>> getNavigationCases()
      {
      if (delegate instanceof ConfigurableNavigationHandler)

      { return ((ConfigurableNavigationHandler) delegate).getNavigationCases(); }

      // I guess
      return null;
      }

      @Override
      public void handleNavigation(FacesContext context, String fromAction, String outcome)
      {
      if (delegate instanceof ConfigurableNavigationHandler) {
      // we need to perform the resolution before JSF gets it so that we know where we are headed
      NavigationCase navigationCase = ((ConfigurableNavigationHandler) delegate).getNavigationCase(context, fromAction, outcome);
      if (navigationCase != null) {
      // this is solved elsewhere in Seam Faces, so just use that same hook
      BeanManager beanManager = ...;
      beanManager.fireEvent(navigationCase, new AnnotationLiteral<Before>() {}, new AnnotationLiteral<FacesNavigation>() {}, new ViewLiteral(context.getViewRoot().getViewId())));
      }
      }
      delegate.handleNavigation(context, fromAction, outcome);
      }

      }

      We could support short-circuiting the view handler by checking for context.getResponseComplete() (redirect occurred) or if the view root changed (render occurred), but that might be abusing this hook.

        Gliffy Diagrams

          Attachments

            Activity

              People

              • Assignee:
                lincolnthree Lincoln Baxter III
                Reporter:
                dan.j.allen Dan Allen
              • Votes:
                0 Vote for this issue
                Watchers:
                0 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: