Programmatic Navigation in WebCenter Portal application – do processAction from Java

Working on a WebCenter 11g Portal application, I recently ran into a challenge: when the user clicks a link in a task flow, the result of that action should be that the user is navigated to another page with a another taskflow that should display content based on context defined through the specific link that was clicked. The challenge was complicated by the fact that the taskflows had to be completely independent, of each other and of the page in which they were embedded.

The general approach with a taskflow that has a link that when clicked should result in effects outside the taskflow is to have the taskflow publish a contextual event with appropriate payload. It is then up to the page that embeds the taskflow in a region to consume and handle the event. That was the easy part.

The event handler can read the payload from the event, store values in a managed bean and navigate to the page that contains the drill-down-target-taskflow. This page has configured the input parameters for this second taskflow using EL expressions that refer to the managed bean that was populated by the event handler. Sounds straightforward, does it not?

What then is the catch in this story? It turned out to be not so straightforward to programmatically arrange for navigation to the specified page.

WebCenter does not work according to the standard JSF navigation model, but instead uses its own Navigation Models that contain pages and other node-types.

Image

Usually navigation is performed through the activation of an action component (command link, command button) that invokes the processAction operation on the Navigation Context.

<af:commandLink text="Return to Dashboard" id="cl12"
                actionListener="#{navigationContext.processAction}">
  <f:attribute name="node"
               value="#{navigationContext.navigationModel['modelPath=/oracle/webcenter/portalapp/navigations/programmaticNavigationModel'].
</af:commandLink>

However, I did not find any clear documentation on how to do navigation programmatically.

After a lot of trial and error and reading through a substantial number of OTN forum threads and blog articles, I put together the following contextual event handler that performs programmatic navigation:

public class PortalEventsHandler {

    private static final String RECORD_DETAILS_PAGE_EL = "#{navigationContext.navigationModel['modelPath=/oracle/webcenter/portalapp/navigations/programmaticNavigationModel'].node['p1']}";
    private static final String CURRENT_CE_CONTEXT_EL = "#{currentCEContext}";
    private static final String RECORD_ID_PAYLOAD_PARAMETER = "recordId";

    public void handleDrilldownEvent(Map payload) {
      // drill down needs to take us to page 1 (with id p1 in the programmatic navigation model)

      // set the selected recordId in the currentCECntext
      Integer recordId = (Integer)payload.get(RECORD_ID_PAYLOAD_PARAMETER);
      CurrentCEContext ceContext = (CurrentCEContext)JSFUtils.resolveExpression(CURRENT_CE_CONTEXT_EL);
      ceContext.setCurrentRecordId( recordId);

      // the processAction method that we need to use for navigation requires an ActionEvent
      // as input; this ActionEvent needs to have a Component as a source
      // this component should have an attribute called node that contains a node from a NavigationModel

      // 1. create the component to put into the Action Event
      Application application = FacesContext.getCurrentInstance().getApplication();
      HtmlCommandButton submitButton = (HtmlCommandButton)application.createComponent(HtmlCommandButton.COMPONENT_TYPE);
      // 2. find the page to navigate to - the nomination details page
      SiteStructureResource node = (SiteStructureResource)JSFUtils.resolveExpression(NOMINATION_DETAILS_PAGE_EL);
      // 3. create the ActionEvent and put the page node into it
      ActionEvent actionEvent = new ActionEvent(submitButton);
      actionEvent.getComponent().getAttributes().put("node", node);
      // 4. get hold of the NavigationContext to invoke the processAction on
      NavigationContext navContext = SiteStructureContext.getInstance();
      navContext.processAction(actionEvent);
    }

What is happening here is that on the fly an ActionEvent is created – since that is what the processAction method expects for an input. The ActionEvent is associated with a UIComponent – also created on the fly – because that is what ActionEvents are and because this component is the carrier of the node attribute that contains the node from Navigation Model to which navigation must be performed.

3 Comments

  1. Navaneet October 24, 2013
  2. Ivo Leitão April 16, 2012
  3. Zafar Siddiqi April 4, 2012