Sunday, March 20, 2011

Region Interaction Example 3 - Using Queue Action Event API

Scenario:
Imagine the following UI:



What we need to do is:
  1. Sync up the right task flow/region with the node selected in the left side tree.
  2. Enable/Disable the Employee/Department command button based on the visible table. For example, if Department table is visible than Employee command button should be visible and vice versa.
  3. Switch the region based on the Employee/Command button clicked.
The following figure explains the scenario:


And after clicking on Departments button, we get:



Constraint:

The database tables are independent of each other as shown below:

CREATE TABLE EMP (
  EMP_ID      NUMBER(10,0) PRIMARY KEY,
  EMP_NAME    VARCHAR2(50) NULL,
  DEPT_ID     NUMBER(10,0) NULL,
  LOCATION_ID NUMBER(4,0)  NULL
);

INSERT INTO EMP VALUES ( 1, 'Emp 1', 1, 1 );
INSERT INTO EMP VALUES ( 2, 'Emp 2', 2, 2 );
INSERT INTO EMP VALUES ( 3, 'Emp 3', 3, 3 );
INSERT INTO EMP VALUES ( 4, 'Emp 4', 4, 4 );
INSERT INTO EMP VALUES ( 5, 'Emp 5', 5, 5 );
INSERT INTO EMP VALUES ( 6, 'Emp 6', 1, 1 );
INSERT INTO EMP VALUES ( 7, 'Emp 7', 2, 2 );
INSERT INTO EMP VALUES ( 8, 'Emp 8', 3, 3 );
INSERT INTO EMP VALUES ( 9, 'Emp 9', 4, 4 );
INSERT INTO EMP VALUES ( 10, 'Emp 10', 5, 5 );

CREATE TABLE DEPT (
  DEPT_ID     NUMBER(10,0) PRIMARY KEY,
  DEPT_NAME   VARCHAR2(50) NULL,
  LOCATION_ID NUMBER(4,0)  NULL
);

INSERT INTO DEPT VALUES ( 1, 'Finance', 1 );
INSERT INTO DEPT VALUES ( 2, 'Sales', 2 );
INSERT INTO DEPT VALUES ( 3, 'Human Resource', 3 );
INSERT INTO DEPT VALUES ( 4, 'BPO', 4 );
INSERT INTO DEPT VALUES ( 5, 'SCM', 5 );

CREATE TABLE LOCATIONS (
  LOCATION_ID    NUMBER(4,0)  PRIMARY KEY ,
  STREET_ADDRESS VARCHAR2(40) NULL
);

INSERT INTO LOCATIONS VALUES (1, 'Location 1');
INSERT INTO LOCATIONS VALUES (2, 'Location 2');
INSERT INTO LOCATIONS VALUES (3, 'Location 3');
INSERT INTO LOCATIONS VALUES (4, 'Location 4');
INSERT INTO LOCATIONS VALUES (5, 'Location 5');

Solution:

1. For tree table node selection, apart from node selection row key setting, you need to refresh the right region programatically.
2. Set the command button disabled property by determining region capabilities.
3. Navigate to the appropriate view using Queueing Action Event API.

Task flow involved for the right region is shown below:


Pasting the code to speak for itself. Key points highlighted. Three files involved (apart from the data model files) majorly.

QueueActionEvent.jspx

<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
  <jsp:directive.page contentType="text/html;charset=UTF-8"/>
  <f:view>
    <af:document id="d1"
                 binding="#{backingBeanScope.backing_QueueActionEvent.d1}">
      <af:messages binding="#{backingBeanScope.backing_QueueActionEvent.m1}"
                   id="m1"/>
      <af:form id="f1"
               binding="#{backingBeanScope.backing_QueueActionEvent.f1}">
        <af:panelSplitter binding="#{backingBeanScope.backing_QueueActionEvent.ps1}"
                          id="ps1">
          <f:facet name="first">
            <af:tree value="#{bindings.LocationVO1.treeModel}" var="node"
                     selectionListener="#{backingBeanScope.backing_QueueActionEvent.onSelection}"
                     rowSelection="single"
                     binding="#{backingBeanScope.backing_QueueActionEvent.t1}"
                     id="t1">
              <f:facet name="nodeStamp">
                <af:outputText value="#{node}"
                               binding="#{backingBeanScope.backing_QueueActionEvent.ot1}"
                               id="ot1"/>
              </f:facet>
            </af:tree>
          </f:facet>
          <f:facet name="second">
            <af:panelGroupLayout layout="scroll"
                                 xmlns:af="http://xmlns.oracle.com/adf/faces/rich"
                                 binding="#{backingBeanScope.backing_QueueActionEvent.pgl1}"
                                 id="pgl1">
              <af:region value="#{bindings.EmpDeptTaskFlow1.regionModel}"
                         id="r1"
                         binding="#{backingBeanScope.backing_QueueActionEvent.r1}"
                         partialTriggers="::t1 ::cb1 ::cb2"/>
              <af:commandButton text="Employees"
                                binding="#{backingBeanScope.backing_QueueActionEvent.cb1}"
                                id="cb1"
                                actionListener="#{backingBeanScope.backing_QueueActionEvent.actionListenerEmpSubmit}"
                                partialSubmit="true"
                                disabled="#{bindings.EmpDeptTaskFlow1.regionModel.capabilities['Department']}"
                                partialTriggers="cb2"/>
              <af:commandButton text="Departments"
                                binding="#{backingBeanScope.backing_QueueActionEvent.cb2}"
                                id="cb2"
                                actionListener="#{backingBeanScope.backing_QueueActionEvent.actionListenerDeptSubmit}"
                                partialSubmit="true"
                                disabled="#{bindings.EmpDeptTaskFlow1.regionModel.capabilities['Employee']}"
                                partialTriggers="cb1"/>
            </af:panelGroupLayout>
          </f:facet>
        </af:panelSplitter>
      </af:form>
    </af:document>
  </f:view>
  <!--oracle-jdev-comment:auto-binding-backing-bean-name:backing_QueueActionEvent-->
</jsp:root>

Backing Bean QueueActionEvent.java

package view.backing;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.MethodExpression;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.PhaseId;
import oracle.adf.view.rich.component.rich.fragment.RichRegion;
import org.apache.myfaces.trinidad.event.SelectionEvent;

public class QueueActionEvent {
    private RichRegion r1;
    private String navigate;
   
    public void actionListenerEmpSubmit(ActionEvent ae){
      this.navigate = "Employee";
      navigateWithinRegion();
    }
   
    public void actionListenerDeptSubmit(ActionEvent ae){
      this.navigate = "Department";
      navigateWithinRegion();
    }
   
    private void navigateWithinRegion(){
      FacesContext fctx = FacesContext.getCurrentInstance();
      ELContext elctx = fctx.getELContext();
      ExpressionFactory expressionFactory = fctx.getApplication().getExpressionFactory();
      MethodExpression methodExpresion = expressionFactory.createMethodExpression(
                                             elctx, navigate,
                                             String.class, new Class[]{}
                                             );
      r1.queueActionEventInRegion( methodExpresion, null, null, false, 0, 0, PhaseId.INVOKE_APPLICATION );
    }
    public void setNavigate(String navigate) {
        this.navigate = navigate;
       
    }
    public String getNavigate() {
        return navigate;
    }
    public void onSelection(SelectionEvent selectionEvent){
      FacesContext fctx = FacesContext.getCurrentInstance();
      ELContext elctx = fctx.getELContext();
      ExpressionFactory expressionFactory = fctx.getApplication().getExpressionFactory();
      MethodExpression methodExpresion = expressionFactory.createMethodExpression(
                                             elctx, "#{bindings.LocationVO1.treeModel.makeCurrent}",
                                             Object.class, new Class[]{selectionEvent.getClass()}
                                             );
      methodExpresion.invoke(elctx, new Object[]{selectionEvent});
      r1.refresh(fctx);
    }
    public void setR1(RichRegion r1) {
        this.r1 = r1;
    }
    public RichRegion getR1() {
        return r1;
    }
}

AMImpl Code

package model;
import model.common.AppModule;
import oracle.jbo.ViewObject;
import oracle.jbo.server.ApplicationModuleImpl;
import oracle.jbo.server.ViewObjectImpl;
// ---------------------------------------------------------------------
// ---    File generated by Oracle ADF Business Components Design Time.
// ---    Sat Mar 19 20:43:03 IST 2011
// ---    Custom code may be added to this class.
// ---    Warning: Do not modify method signatures of generated methods.
// ---------------------------------------------------------------------
public class AppModuleImpl extends ApplicationModuleImpl implements AppModule {
    /**
     * This is the default constructor (do not remove).
     */
    public AppModuleImpl() {
    }
    /**
     * Container's getter for EmpVO1.
     * @return EmpVO1
     */
    public ViewObjectImpl getEmpVO1() {
        return (ViewObjectImpl)findViewObject("EmpVO1");
    }
    /**
     * Container's getter for DeptVO1.
     * @return DeptVO1
     */
    public ViewObjectImpl getDeptVO1() {
        return (ViewObjectImpl)findViewObject("DeptVO1");
    }
   
    public void executeDeptVOUsingLocation(oracle.jbo.domain.Number locId){
      ViewObject vo = this.getDeptVO1();
      // Set the two design time named bind variables
      vo.setWhereClause("location_id = :TheLocId");
      vo.defineNamedWhereClauseParam("TheLocId", null, null);
      vo.setNamedWhereClauseParam("TheLocId", locId);
      vo.executeQuery();
    }

    public void executeEmpVO(oracle.jbo.domain.Number deptId){
      ViewObject vo = this.getEmpVO1();
      // Set the two design time named bind variables
      vo.setWhereClause("dept_id = :TheDeptId");
      vo.defineNamedWhereClauseParam("TheDeptId", null, null);
      vo.setNamedWhereClauseParam("TheDeptId", deptId);
      vo.executeQuery();
    }
   
    public void executeEmpVOUsingLocation(oracle.jbo.domain.Number locId){
      ViewObject vo = this.getEmpVO1();
      // Set the two design time named bind variables
      vo.setWhereClause("location_id = :TheLocId");
      vo.defineNamedWhereClauseParam("TheLocId", null, null);
      vo.setNamedWhereClauseParam("TheLocId", locId);
      vo.executeQuery();
    }   
    /**
     * Container's getter for LocationVO1.
     * @return LocationVO1
     */
    public ViewObjectImpl getLocationVO1() {
        return (ViewObjectImpl)findViewObject("LocationVO1");
    }
}

Task Flow Source Code:

<?xml version="1.0" encoding="windows-1252" ?>
<adfc-config xmlns="http://xmlns.oracle.com/adf/controller" version="1.2">
  <task-flow-definition id="EmpDeptTaskFlow">
    <default-activity id="__2">executeEmpVOUsingLocation</default-activity>
    <input-parameter-definition id="__7">
      <name id="__8">locationId</name>
      <value>#{pageFlowScope.locId}</value>
      <class>oracle.jbo.domain.Number</class>
    </input-parameter-definition>
    <managed-bean id="__6">
      <managed-bean-name id="__3">backing_DeptView</managed-bean-name>
      <managed-bean-class id="__4">view.backing.DeptView</managed-bean-class>
      <managed-bean-scope id="__5">backingBean</managed-bean-scope>
      <!--oracle-jdev-comment:managed-bean-jsp-link:1DeptView.jsff-->
    </managed-bean>
    <view id="DeptView.jsff">
      <page>/DeptView.jsff</page>
    </view>
    <method-call id="executeDeptVOUsingLocation">
      <method>#{bindings.executeDeptVOUsingLocation.execute}</method>
      <outcome id="__9">
        <fixed-outcome>executeDeptVOUsingLocation</fixed-outcome>
      </outcome>
    </method-call>
    <method-call id="executeEmpVOUsingLocation">
      <method>#{bindings.executeEmpVOUsingLocation.execute}</method>
      <outcome id="__20">
        <fixed-outcome>executeEmpVOUsingLocation</fixed-outcome>
      </outcome>
    </method-call>
    <view id="EmplView">
      <page>/EmplView.jsff</page>
    </view>
    <control-flow-rule id="__15">
      <from-activity-id id="__16">executeDeptVOUsingLocation</from-activity-id>
      <control-flow-case id="__17">
        <to-activity-id id="__18">DeptView.jsff</to-activity-id>
      </control-flow-case>
    </control-flow-rule>
    <control-flow-rule id="__21">
      <from-activity-id id="__22">DeptView.jsff</from-activity-id>
      <control-flow-case id="__24">
        <from-outcome id="__25">Employee</from-outcome>
        <to-activity-id id="__23">executeEmpVOUsingLocation</to-activity-id>
      </control-flow-case>
    </control-flow-rule>
    <control-flow-rule id="__32">
      <from-activity-id id="__33">executeEmpVOUsingLocation</from-activity-id>
      <control-flow-case id="__35">
        <to-activity-id id="__36">EmplView</to-activity-id>
      </control-flow-case>
    </control-flow-rule>
    <control-flow-rule id="__37">
      <from-activity-id id="__38">EmplView</from-activity-id>
      <control-flow-case id="__40">
        <from-outcome id="__41">Department</from-outcome>
        <to-activity-id id="__39">executeDeptVOUsingLocation</to-activity-id>
      </control-flow-case>
    </control-flow-rule>
    <use-page-fragments/>
  </task-flow-definition>
</adfc-config>

That's it.

JDev Release 11.1.1.4

No comments:

Post a Comment