Monday, May 28, 2012

Commit the child taskflow transaction in parent taskflow transaction using DataContolFrame Api

In this post I'm sharing sample for how can we use "DataContolFrame" to commit the child taskflow transaction in parent taskflow transaction. 

Take a scenario, where we have two taskflows. The parent taskflow contain employee table and child taskflow contains selected employee rows. Alter the values and save, once clicking on Save button will save the data into cache. Now in parent taskflow user can click on Commit button would commit all the changes down in the child taskflow to DB, Rollback button will undo all changes done in child taskflow.

Here DataControlFrame api is used to commit/rollback the data at taskflow controller level. A Data Control Frame is the container associated with a task flow that contains data control instances. To specify whether data control instances are shared between the calling and called task flows, you must set a data-control-scope value of either shared or isolated on the called bounded task flow. In above scenario we can use shared data-control-scope. 

[Runs with Oracle JDeveloper 11.1.2.0.0 (11g R2) + HR Schema]

Implementation Steps

Create Fusion Web Application with business components from tables based on Departments, Employees table, create a new extended object from Employees View as shown in below image.


Open the AppModule and select Data Model tab move "childEmployeesView" from available view objects to data model.


Next go to Java tab in AppModule and click on edit java options. Generate the application module class: AppModuleImpl.java.

Open the AppModuleImpl.java file and the below methods code.
/**
 * This method create's the view crietria at the runtime,
 * set the IN clause operator by accessing the ChildEmployeesView1
 * @param empList
 */
public void populateSelectedRowData(List empList) {
 try {
  if (empList.size() > 0) {
   //cleanUpChildEmployeesView1 just in case before populating new set of rows
   cleanUpChildEmployeesView1();
   ViewObject childEmpVo = getChildEmployeesView1();
   ViewCriteria childEmpVC = childEmpVo.createViewCriteria();
   ViewCriteriaRow childEmpVCRow = childEmpVC.createViewCriteriaRow();
   ViewCriteriaItem childEmpVCRowItem = childEmpVCRow.ensureCriteriaItem("EmployeeId");
   childEmpVCRowItem.setOperator("IN");
   for (int i = 0; i < empList.size(); i++) {
    childEmpVCRowItem.setValue(i, empList.get(i));
   }
   childEmpVC.addElement(childEmpVCRow);
   childEmpVo.applyViewCriteria(childEmpVC);
   childEmpVo.executeQuery();
   System.out.println("populateSelectedRowData - Estimated Row Count - " +
          childEmpVo.getEstimatedRowCount());
  }
 } catch (Exception e) {
  e.printStackTrace();
 }
}

/**
 * Clean up the childemployeesView existing rows from collection.
 */
public void cleanUpChildEmployeesView1() {
 ViewObject childEmpVO = (ViewObject)this.getChildEmployeesView1();
 //avoid validation when navigating rows
 childEmpVO.setRowValidation(false);
 while (childEmpVO.hasNext()) {
  childEmpVO.setCurrentRow(childEmpVO.next());
  childEmpVO.removeCurrentRowFromCollection();
 }
}

/**
 * This method will update the departmentId for selected Employees rows
 * @param empKeysList
 * @param departmentId
 */
public void updateAllChildEmployeesRows(List empKeysList, String departmentId) {
 if (empKeysList != null && empKeysList.size() > 0) {
  ViewObject empVO = (ViewObject)this.getEmployeesView1();
  Iterator iter = empKeysList.iterator();
  Key rowKey = null;
  Row[] matchingInvoiceRows = null;
  Row currRow = null;
  while (iter.hasNext()) {
   //get the key for the invoice row
   rowKey = (Key)iter.next();
   //find the row by key in InvoiceVO
   matchingInvoiceRows = empVO.findByKey(rowKey, 1);
   if (matchingInvoiceRows != null && matchingInvoiceRows.length > 0)
    currRow = matchingInvoiceRows[0];
   if (currRow != null) {
    if (departmentId != null) {
     currRow.setAttribute("DepartmentId", departmentId);
    }
   }
  }
 }
}

Go back to AppModule.xml and select Java tab in client interface section move populateSelectedRows, updateAllChildEmployeesRows from available to selected block.


In ViewController project, create below mentioned bounded taskflows.
  1. "EmployeeDetails-btf" and set the Transaction as "Always Begin New Transaction", select the data-control-scope "Shared data controls with calling task flow".
  2. "EmployeeEdit-btf" and set the Transaction as "Always Use Existing Transaction", select the data-control-scope "Shared data controls with calling task flow" and create two pageFlowScope parameters as empList and empKeyList.
Open EmployeeDetail-btf, from component palette drop view as "EmployeeDetails" and generate EmployeeDetails.jsff page and "EmployeeDetailsBean.java". Add the EmployeeDetailsBean.java file in taskflow with scope requestScope.
  • From data control palette drag and drop EmployeesView1->Table as ADF Read Only Table, set RowSelection as "muliptle". 
  • Surround the table with panel collection component and add Edit button with text as "Edit". Create the actionListener method for edit button as "onEditAction".
  • Add two more button to the page Commit/Rollback and create actionListener method as "onCommit","onRollback" respectively.
  • From component palette drop popup inside the page and drop "EmployeeEdit-btf" as region inside popup, set the popupCanceledListener, popupFetchListener as show in the below code.
 <af:popup childCreation="deferred" autoCancel="disabled" id="p1" contentDelivery="lazyUncached"
              popupCanceledListener="#{EmployeeDetailsBean.popupCancelled}"
              popupFetchListener="#{EmployeeDetailsBean.poupFetchListener}" binding="#{EmployeeDetailsBean.popup}">
        <af:panelWindow id="pw1" title="Edit Employees">
            <af:region value="#{bindings.EmployeeEditbtf1.regionModel}" id="r1"
                       regionNavigationListener="#{EmployeeDetailsBean.hearNavigation}"/>
        </af:panelWindow>
  </af:popup>

Open the EmployeeDetailsBean.java file and copy the below methods code.
private RichPopup popup;
private RichTable empTable;

public EmployeeDetailsBean() {
}

public void setPopup(RichPopup popup) {
 this.popup = popup;
}

public RichPopup getPopup() {
 return popup;
}

public void setEmpTable(RichTable empTable) {
 this.empTable = empTable;
}

public RichTable getEmpTable() {
 return empTable;
}

public void popupCancelled(PopupCanceledEvent popupCanceledEvent) {
 ADFContext.getCurrent().getPageFlowScope().put("forceActivate", "false");
 System.out.println("popupCancelled");
}

public void poupFetchListener(PopupFetchEvent popupFetchEvent) {
 ADFContext.getCurrent().getPageFlowScope().put("forceActivate", "true");
 System.out.println("poupFetchListener");
}

public void hearNavigation(RegionNavigationEvent regionNavigationEvent) {
 this.popup.hide();

 AdfFacesContext.getCurrentInstance().addPartialTarget(this.empTable);
 System.out.println("Finished closing popup");
}

public void onEditAction(ActionEvent actionEvent) {
 RowKeySet selectedEmps = getEmpTable().getSelectedRowKeys();
 if (selectedEmps.size() > 0) {
  //Restart the taskflow
  DCBindingContainer dc = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
  DCTaskFlowBinding tf = (DCTaskFlowBinding)dc.findExecutableBinding("EmployeeEditbtf1");
  tf.getRegionModel().refresh(FacesContext.getCurrentInstance());

  Iterator selectedEmpIter = selectedEmps.iterator();
  DCBindingContainer bindings = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
  DCIteratorBinding empIter = bindings.findIteratorBinding("EmployeesView1Iterator");
  RowSetIterator empRSIter = empIter.getRowSetIterator();
  List selectedRowKeys = new ArrayList();
  List SelectedDeptIdRowValue = new ArrayList();
  while (selectedEmpIter.hasNext()) {
   Key key = (Key)((List)selectedEmpIter.next()).get(0);
   selectedRowKeys.add(key);
   Row currentRow = empRSIter.getRow(key);
   SelectedDeptIdRowValue.add(currentRow.getAttribute("EmployeeId"));
  }

  ADFContext.getCurrent().getRequestScope().put("empList", SelectedDeptIdRowValue);
  ADFContext.getCurrent().getRequestScope().put("empKeysList", selectedRowKeys);
  RichPopup.PopupHints hints = new RichPopup.PopupHints();
  this.popup.show(hints);
 }
}

public void onCommit(ActionEvent actionEvent) {
 Map sessionMap = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
 BindingContext context = (BindingContext)sessionMap.get(BindingContext.CONTEXT_ID);
 String currentFrameName = context.getCurrentDataControlFrame();
 DataControlFrame dcFrame = context.findDataControlFrame(currentFrameName);
 dcFrame.commit();
 dcFrame.beginTransaction(null);
}

public void onRollBack(ActionEvent actionEvent) {
 Map sessionMap = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
 BindingContext context = (BindingContext)sessionMap.get(BindingContext.CONTEXT_ID);
 String currentFrameName = context.getCurrentDataControlFrame();
 DataControlFrame dcFrame = context.findDataControlFrame(currentFrameName);
 dcFrame.rollback();
 dcFrame.beginTransaction(null);
 AdfFacesContext.getCurrentInstance().addPartialTarget(this.empTable);
}

Now go to EmployeeDetails.jsff page binding and set the condition for taskflow-EmployeeEditbtf1 executables as shown in below image.



Open the EmployeeEdit-btf, create the flow as shown below.



  • Drag and drop populateSelectedRowData from data control and set the parameter value for empList as "#{pageFlowScope.empList}".
  • From component palette drop view as "EmployeeEdit" and generate EmployeeEdit.jsff page and "EmployeeEditBean.java". Add the EmployeeEditBean.java file in taskflow with scope backingBean.
  • Draw the control flow case from  populateSelectedRowData to EmployeeEdit and keep default outcome
  • Drop  EmployeesView1->Execute from data control palette.
  • Draw the control flow case from EmployeeEdit to Execute and outcome as save.
  • Now add two Task Flow Return and name them as Save and Cancel.
  • Draw the control flow case from EmployeeEdit to Cancel and outcome as exit.
  • Draw the control flow case from Execute to Save and outcome as Execute.
Open EmployeeEdit.jsff page.
  • From data control palette drop ChildEmployeesView1->Table as ADF Table.
  • Drop DepartmentView1->Single Selection as ADF Select One Choice and select display attribute as departmentId and create valueChangeListener method as "getSelectedDeptId".
  • Go to page bindings page, add method action updateAllChildEmployeesRows  set the parameters value for empKeyList as "#{pageFlowScope.empList}" and departmentId as "#{pageFlowScope.departmentId}".
  • From component palette add two button as Save/Cancel and set the action to save/exit respectively.
Open the EmployeeEditBean page and add the below code.
public void getSelectedDeptId(ValueChangeEvent valueChangeEvent) {
        ADFContext.getCurrent().getPageFlowScope().put("departmentId", valueChangeEvent.getNewValue());
    }

Last step create the index.jspx page and drop EmployeeDetail-btf as region. Run the index.jspx page and page should look like below.


Select multiple employee rows and click on edit button.


Select the required DepartmentId and click on Save button will save the data in cache not to the DB. If Cancel button is clicked no action will happen, it will just close the popup window.


Now we can notice the departmentId for the selected employee rows as updated. In this page if Commit button is clicked DataControlFrame will update the child taskflow values to the database and Rollback button will undo all the changes.

Thursday, May 24, 2012

Dynamic Control Flow Case using ActionEvent

Here is a scenario where we need to navigate from one page to another page based on some condition. In design time set the 'Action' property of UI component can be used to navigate between pages, but here Action property can't be used since navigation is based on condition. In this article will see how can we programmatically handle the control flow case in managed bean using ActionEvent.

This can be achieved using handleNavigation method from NavigationHandler class. But direct invocation of methods on the NavigationHandler doesn't conform with JSF specification and it bypasses JSF lifecycle invoke application phase, also pending changes may not be submitted.

Take an example, here we have DeptBrowsePage which display departments table with multiple select option enabled and with edit button. If user selects the single row and click on edit Control Flow Case should go to DeptFormPage and if multiple rows selected it should go to DeptTablePage.

You can download the sample workspace from here
[Runs with Oracle JDeveloper 11.1.2.0.0(11g R2) + HR Schema]

The following code illustrates the Control Flow Case dynamically at run time using handleNavigation method. Please download the application to see the entire scenario.

Note: - Here created the bindings for buttons DeptForm, DeptButton respective with getDeptFormButton(), getDeptTableButton() and buttons rendered property made false.
/**
* In this method first looking for the selected row keys
* Based on the condition, queue the action event on respective command button
* @return
*/
public String navigateHanlderMethod() {
        //Get the selected rowkey values
        RowKeySet selectedDepts = getDeptTable().getSelectedRowKeys();
        if (selectedDepts.size() == 1) { //If Single row is selected
            ActionEvent actionEvent = new ActionEvent(this.getDeptFormButton());
            actionEvent.queue();
        } else if (selectedDepts.size() > 1) { // If multiple rows are selected
            List selectedRowKeys = getSelectedRowKeys();
            Map pfScope = ADFContext.getCurrent().getPageFlowScope();
            pfScope.put("deptList", selectedRowKeys);
            ActionEvent actionEvent = new ActionEvent(this.getDeptTableButton());
            actionEvent.queue();
        }
        return null;
 }

Output: Run the index.jspx page.


Select single row and click on the Edit button should take to DeptFormPage.jspx and display only selected row.


Select multiple rows and click on the Edit button should take to DeptTablePage.jspx and display only selected rows.

Monday, May 21, 2012

Get ViewObject attributes pro-grammatically and display in Shuttle component

In this article, I'm trying to explain how can ViewObject attributes be read pro-grammatically and display these attributes in ADF Shuttle component.

The ADF Shuttle component is appropriate for when the business process requires sequencing selected objects for further action, and the user needs to see the source data and items selected for process. The above scenario can be useful when you want to compare two objects, where in user can quickly add and remove items from the pool. Here database table column will be displayed as comparable fields.

You can download the sample workspace from here
[Runs with Oracle JDeveloper 11.1.2.0.0 (11g R2) + HR Schema]

Implementation steps

Create a Fusion Web Application, click on ADF Business Components and create business components from table based on Employees. Create a CompareAttributes.java class file and add the below code.

public class CompareAttributes {
 private String columnName;
 private String columnAliasName;

 public CompareAttributes() {
  super();
 }

 public CompareAttributes(String columnName, String columnAliasName) {
  super();
  this.columnName = columnName;
  this.columnAliasName = columnAliasName;
 }

 public void setColumnName(String columnName) {
  this.columnName = columnName;
 }

 public String getColumnName() {
  return columnName;
 }

 public void setColumnAliasName(String columnAliasName) {
  this.columnAliasName = columnAliasName;
 }

 public String getColumnAliasName() {
  return columnAliasName;
 }
}

Open the AppModule.xml and goo to Java tab in AppModule and click on edit java options. Generate the application module class: AppModuleImpl.java and open the AppModuleImpl.java file and the below method code.

/**
* This method reads the ViewObject attributes and populate CompareAttributes list 
* @return CompareAttributes list
*/
public List getCompareAttributes() {
 ViewObjectImpl vo = getEmployeesView1();
 ViewAttributeDefImpl[] attrDefs = vo.getViewAttributeDefImpls();
 int count = 0;
 List compareAttrs = new ArrayList();
 for (ViewAttributeDefImpl attrDef : attrDefs) {
  byte attrKind = attrDefs[count].getAttributeKind();
  //checks attribute kind for each element in an array of AttributeDefs
  if (attrKind != AttributeDef.ATTR_ASSOCIATED_ROW && attrKind != AttributeDef.ATTR_ASSOCIATED_ROWITERATOR) {
   String columnName = attrDef.getName();
   String columnAliasName = attrDef.getAliasName();
   compareAttrs.add(new CompareAttributes(columnName, columnAliasName));
   count++;
  }
 }
 return compareAttrs;
}

Go back to AppModuleImpl.java and select Java tab in client interface section move getCompareAttributes from available to selected block.


In ViewController project, create index.jspx page and generate page definition page. Go to bindings tab and insert methodAction as "getCompareAttributes" from AppModuleDataControl.

Create the managedBean as "IndexBean", set the scope as pageFlowScope and copy the below code.

public List getShuttleList() {
        BindingContainer bindings = BindingContext.getCurrent().getCurrentBindingsEntry();
        OperationBinding operBind = bindings.getOperationBinding("getCompareAttributes");
        List<CompareAttributes> compareAttr = (List)operBind.execute();

        List shuttleList = new ArrayList();
        for (int i = 0; i < compareAttr.size(); i++) {
            CompareAttributes attr = compareAttr.get(i);
            SelectItem item = new SelectItem(i, attr.getColumnName(), attr.getColumnAliasName());
            shuttleList.add(item);
        }
        return shuttleList;
    }

Open index.jspx page and from component palette drag and drop the Shuttle Component, In Insert shuttle window for "Bind to list (select items) bind to #{pageFlowScope.IndexBean.shuttleList}" as shown below.


Run the index.jspx page, now user can quickly add and remove items from the pool.


Saturday, May 19, 2012

EJB DataControl - Configuring Sequential ids using JPA @TableGenerator

In this article I'm trying to explain how JPA feature used to generate and assign the unique sequence numbers to JPA entity using @TableGenerator.

You can download the sample workspace from here
[Runs with Oracle JDeveloper 11.1.2.0.0 (11g R2) + HR Schema]

Implementation steps

Create Fusion Web Application with entities based on Departments, then create a session bean and data control for the session bean.

First create the table required for @TableGenerator, download the required sql script.

Steps to configure @TableGenerator
  1. Right click on the Connection  and select New -> Offline Database Objects -> Offline Database Objects from Source Database, select Sequence table and click on Finish.
  2. Open persistence.xml in flat editor.
  3. Navigate to Departments Entity from persistence.xml and open departmentId field.
  4. Go to Primary Key Generation Tab select Table Generator section.
  5. Make the configuration as shown in below image.

Above Primary key section will have the configuration details of the table generator to be used Column field specifies the Sequence name column, the name of the Table Generator set in Name field should match the Sequence name present in the table and Value column field specifies the Sequence count column.

Now select Use Generated Value check box and set the Strategy as Table and Generator as DeptNoGenerator as shown below.


In View Controller project, create the index.jspx page and drop the departmentsFindAll->Table as ADF Table and drop the Create operation from departmentsFindAll->Operations as ADF Button.
From Data Control Palette drop persistDepartments as ADF Button and bind parameter as shown below.


Run the index.jspx page and click on create button and enter the filed details, don't enter for departmentId field and save the record. Now the departmentId will be added as 101 since we have started sequence number from 100.

Wednesday, May 16, 2012

Bean DataControl - Edit table records

Here is a scenario where we need to edit the table records and update them, here table is based on Bean DataControl. so in this article, I'm trying to explain how can we edit the table records using Bean DataControl.

You can download the sample workspace from here
[Runs with Oracle JDeveloper 11.1.2.0.0 (11g R2) + HR Schema] 

Implementation Steps

Create Fusion Web Application, create the DeptBean.java, EmpBean.java and GenericBean.java classes in model project and paste the below code.

Open DeptBean.java and paste the below code.
public class DeptBean {
    private String deptNo;
    private String deptName;
    private Collection empsCollection = new ArrayList();

    public DeptBean() {
        super();
    }
    public DeptBean(String dno, String dname, Collection emps) {
        this.deptNo = dno;
        this.deptName = dname;
        this.empsCollection = emps;
    }

    public void setDeptNo(String deptNo) {
        this.deptNo = deptNo;
    }

    public String getDeptNo() {
        return deptNo;
    }

    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }

    public String getDeptName() {
        return deptName;
    }

    public void setEmpsCollection(Collection empsCollection) {
        this.empsCollection = empsCollection;
    }

    public Collection getEmpsCollection() {
        return empsCollection;
    }
}

Open EmpBean.java and paste the code.
public class EmpBean {
    private String deptNo;
    private String empId;
    private String empName;

    public EmpBean() {
        super();
    }

    public EmpBean(String id, String name, String dno) {
        this.deptNo = dno;
        this.empId = id;
        this.empName = name;
    }

    public void setDeptNo(String deptNo) {
        this.deptNo = deptNo;
    }

    public String getDeptNo() {
        return deptNo;
    }

    public void setEmpId(String empId) {
        this.empId = empId;
    }

    public String getEmpId() {
        return empId;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public String getEmpName() {
        return empName;
    }
}

Open GenericBean.java and paste the below method code.
/**
* Creating a List which has 10 departments
* and 5 employees in each department.
* @return DeptBean list
*/
public List populateBean() {
 List deptList = new ArrayList();
 int noOfDepts = 1;
 while (noOfDepts < 11) {
  String deptNo = "" + noOfDepts;
  String deptName = "DeptName_" + noOfDepts;

  List empList = new ArrayList();
  int noOfEmps = 1;
  while (noOfEmps < 6) {
   String empId = deptNo + noOfEmps;
   String empName = "EmpName_" + deptName + "_" + empId;
   EmpBean emp = new EmpBean(empId, empName, deptNo);
   empList.add(emp);
   noOfEmps++;
  }
  DeptBean dept = new DeptBean(deptNo, deptName, empList);
  deptList.add(dept);
  noOfDepts++;
 }
 return deptList;
}

Now right click on GenericBean.java file and generate data control. Open the DataControl.dcx file in application navigator and select the GenericBean. Go to the GenericBean property inspector and set SupportsTransactions as true.

In the ViewController create index.jspx page, create adf bounded task flow "BeanDCEditable-btf" and from component palette drag and drop two view BrowsePage.jsff, EditPage,jsff. Now draw a navigation case from BrowsePage to EditPage and change outcome to "edit" and draw a navigation case from EditPage to BrowsePage and change outcome to "browse".

Open BrowsePage.jsff, from data control palette drop populateBean->DeptBean->empsCollection->Master-Details as ADF Master Form, Detail table and RowSelection as Single. From component palette drop a button and Action as "Edit".

Open EditPage.jsff, from data control palette drop populateBean->DeptBean->empsCollection->Form as ADF Form and include Submit button with Action as "browse".

Open the index.jspx page, drop the BeanDCEditable-btf as region and run the index.jspx page. Once the page load select the any row in the empsCollection table, change the EmpName value and submit the page. Now validate that the changes made in the editPage are visible in browsePage as show below image.

Tuesday, May 15, 2012

Display Lookup values from related ejb entities using JOIN FETCH

JOIN FETCH - The purpose of JOIN FETCH is to fetch the related objects from the database in a single query. So in this article, I'm trying to explain how can we use jpql JOIN FETCH and expose those attributes to EJB data control layer.

Take a scenario, where we need to build ADF tree based on departments,employees and location tables. While displaying the tree, root node should display departmentName along with city attribute which is stored in related object Location table.


In BC4J, this scenario can be implemented using Entity Objects facility provided in View Object layer. These entity objects are used by the view object for accessing the related objects attributes and will be exposed in data control layer automatically. In my previous post I have showed on "how to add attribute from related entity in view object".

Same behavior can be implemented in EJB using JOIN FETCH. Using this query improves the efficiency of iteration over the result Departments objects because it eliminates the need for retrieving the associated Locationobjects separately.So in single query related objects attributes is also fetched from the database.

You can download the sample workspace from here
[Runs with Oracle JDeveloper 11.1.2.0.0 (11g R2) + HR Schema]

Implementation Steps

Create Java EE Web Application with entities based on Departments, Employees and Location table, then create a session bean and data control for the session bean. Open the departments entity and alter the named query as below.
@NamedQuery(name = "Departments.findAll",
                             query = "select o from Departments o join fetch o.locations")
Note:- The query above returns Departments instances and guarantees that the locations attributes will already be fetched in the returned instances.

Now we need to expose the location attribute values to data control, create a Transient variable called "city" and add the below code in department entity.

@Transient
 private String city;
 
public String getCity() {
  return this.locations.getCity();
}

Note: Can create sample java client to check whether the city attribute value is coming in departments instance before proceeding to data control.

In the ViewController create index.jspx page, from data control palette drop departmentsFindAll->Tree as ADF Tree and in edit tree bindings select the attributes as shown in below image.


Run the index.jspx page. Now notice root node will display departmentName along with city attribute value also.

How to add attribute from related entity in view object

Take as scenario where we need to retrieve the related objects attributes in the same result set. In this article, I'm trying to explain how can we add attribute from related entity in view object. 

In BC4J, this scenario can be implemented using Entity Objects facility provided in View Object layer. These entity objects are used by the view object for accessing the related objects attributes and will be exposed in data control layer automatically.

Implementation Steps

Create Fusion Web Application, click on ADF Business Components and create business components from table based on Departments, Employees.

Open the EmployeesView.xml view object and select the Entity Objects tab. Move the Departments entity from available pool to selected pool as shown below.


Go to the Attributes tab, click on add attribute from entity. In Attributes window under Departments entity section move DepartmentName from available pool to selected pool as shown below.


Run the ADF Module Tester(application module) and select EmployeesView1 in AppModule. Now we can notice DepartmentName attribute is also displayed for the employee result set.

Monday, May 14, 2012

EJB DataControl - programmatically construct Master-Detail hierarchy

Sometimes, in EJB data control it is necessary to construct Master-Detail relationships across different levels pro-grammatically. One of the most common use cases is construct the master-detail relation based on database tables where tables doesn't have foreign key relationship. So in this article, I'm trying to construct master-detail hierarchy pro-grammatically by taking simple custom_dept, custom_emp tables.

You can download the sample workspace from here
[Runs with Oracle JDeveloper 11.1.2.0.0 (11g R2) + HR Schema]

Note:- In Bean Data Control, Master-Detail hierarchy can be constructed as a same way but  java bean classes to be created first and then pro-grammatically populate the data in session facade.

Model Diagram:



Implementation Steps

Create Java EE Web Application with entities based on custom_dept and custom_emp tables, then create a session bean and data control for the session bean. Open cusotm_dept entity and create a transient variable called "empCollection" and add the below code.
@Transient
private Collection empCollection = new ArrayList();

public void setEmpCollection(Collection empCollection) {
   this.empCollection = empCollection;
}

public Collection getEmpCollection() {
   return empCollection;
}

Open session facade, add the below code to the session facade and expose the masterDetailFindAll() method in local/remote interface and generate a data control for that.

Note:- Here in the below code "em" is a EntityManager.
public List masterDetailFindAll() {
String deptQueryString = "select * from custom_dept";
Query deptSearchQuery = em.createNativeQuery(deptQueryString, "deptQuery");
List deptResultList = deptSearchQuery.getResultList();
Iterator deptListIterator = deptResultList.iterator();
List deptList = new ArrayList();
while (deptListIterator.hasNext()) {
     Object deptCol[] = (Object[])deptListIterator.next();
     CustomDept dept = new CustomDept();
     BigDecimal departmentId = (BigDecimal)deptCol[0];
     dept.setDepartmentId(departmentId);
     dept.setDepartmentName((String)deptCol[1]);
     dept.setLocationId((BigDecimal)deptCol[2]);
     String empQueryString =
       "select * from custom_emp emp, custom_dept dept where emp.department_id = dept.department_id and dept.department_id = " +
     departmentId;
     Query empSearchQuery = em.createNativeQuery(empQueryString, "empQuery");
     List empResultList = empSearchQuery.getResultList();
     Iterator empListIterator = empResultList.iterator();
     List empList = new ArrayList();
     while (empListIterator.hasNext()) {
          Object empCol[] = (Object[])empListIterator.next();
          CustomEmp emp = new CustomEmp();
          emp.setEmployeeId((BigDecimal)empCol[0]);
          emp.setFirstName((String)empCol[1]);
          emp.setLastName((String)empCol[2]);
          emp.setEmail((String)empCol[3]);
          emp.setJobId((String)empCol[4]);
          emp.setDepartmentId((BigDecimal)empCol[5]);
          empList.add(emp);
     }
     dept.setEmpCollection(empList);
     deptList.add(dept);
 }
  return deptList;
}

In the ViewController create index.jspx page, from data control palette drag and drop masterDetailFindAll()->CustomDept->empCollection->Master-Detail as ADF Master Form, Detail Table.

Run the index.jspx page, now we can traverse through Master-Detail records.


Friday, May 11, 2012

Display multiple selected rows from ADF table in a popup window

In this post I'm sharing sample for how to display multiple selected rows from ADF table in a popup window.

Solution
Create a new extended view from the parent view. In Application Module create a view criteria with IN clause at run time and execute the view, this is one of the approach to display the contents of all the selected rows in a popup window.

You can download the sample workspace from here
[Runs with Oracle JDeveloper 11.1.2.0.0 (11g R2) + HR Schema]

Implementation Steps

Create Fusion Web Application with business components from tables based on Departments table. Now create a new extended object from DepartmentsView as shown in below image.


 Open the AppModule and select Data Model tab move "childDepartmentsView" from available view objects to data model.


 Next go to Java tab in AppModule and click on edit java options. Generate the application module class: AppModuleImpl.java.
Open the AppModuleImpl.java file and the below method code.

/**
 * This method create's the view crietria at the runtime,
 * set the IN clause operator by accessing the ChildDepartmentsView1
 * @param deptList
 */
public void populateSelectedRows(List deptList) {
 try {
    ViewObject childDeptVo = getChildDepartmentsView1();
    ViewCriteria childDeptVC = childDeptVo.createViewCriteria();
    ViewCriteriaRow childDeptVCRow = childDeptVC.createViewCriteriaRow();
    ViewCriteriaItem childDeptVCRowItem = childDeptVCRow.ensureCriteriaItem("DepartmentId");
    childDeptVCRowItem.setOperator("IN");
    for (int i = 0; i < deptList.size(); i++) {
      childDeptVCRowItem.setValue(i, deptList.get(i));
    }
    childDeptVC.addElement(childDeptVCRow);
    childDeptVo.applyViewCriteria(childDeptVC);
    childDeptVo.executeQuery();
 } catch (Exception e) {
    e.printStackTrace();
 }
}   

Go back to AppModuleImpl.java and select Java tab in client interface section move populateSelectedRows from available to selected block.


In ViewController project, create index.jspx page and drag and drop DepartmentsView1->Table as ADF Read-only Table with rowSlection as multiple and create the backingBean as "IndexBean". Surround the table with panel collection, add the toolbar, drop button inside toolbar and name as "Edit".

From component palette drag and drop ADF popup, ContinentDelivery as lazyUncached. Drop dialog inside the popup, Type as none. Now drag and drop  ChildDepartmentsView1->Table as ADF Table.

Open the index.jspx page, bind the departments table to the backing bean as show below.


Create the ActionListener method called "editAction" for Edit button.


Open the IndexBean backing bean and add the below method code.

private List selectedRowKeys;

public void editAction(ActionEvent actionEvent) {
        getSelectedRowKeys();

        BindingContainer bindings = BindingContext.getCurrent().getCurrentBindingsEntry();
        OperationBinding oper = bindings.getOperationBinding("populateSelectedRows");
        oper.execute();

        ExtendedRenderKitService erkService =
            Service.getService(FacesContext.getCurrentInstance().getRenderKit(), ExtendedRenderKitService.class);
        erkService.addScript(FacesContext.getCurrentInstance(),
                             "var hints = {autodismissNever:true}; " + "AdfPage.PAGE.findComponent('p1').show(hints);");
    }

    public List getSelectedRowKeys() {
        selectedRowKeys = null;
        RowKeySet selectedDepts = getDeptTable().getSelectedRowKeys();
        Iterator selectedDeptIter = selectedDepts.iterator();
        DCBindingContainer bindings = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
        DCIteratorBinding deptIter = bindings.findIteratorBinding("DepartmentsView1Iterator");
        RowSetIterator deptRSIter = deptIter.getRowSetIterator();
        selectedRowKeys = new ArrayList();
        while (selectedDeptIter.hasNext()) {
            Key key = (Key)((List)selectedDeptIter.next()).get(0);
            Row currentRow = deptRSIter.getRow(key);
            selectedRowKeys.add(currentRow.getAttribute("DepartmentId"));
        }
        return selectedRowKeys;
    } 

Go to Bindings tab in index.jspx page, add populateSelectedRows method action and map the parameter to backingBeanScope variable.


Run the index.jspx page, select the multiple rows and click on edit button. Popup window should contains all the selected rows as shown below.

Tuesday, May 8, 2012

Update multiple rows using EJB Data Control

Let us take a scenario where in users wants to edit multiple records in the ADF table. So in ejb this can't be achieved in straight forward way, we have to manually get all the selected row keys and merge them to the database in programmatic way.

You can download the sample workspace from here
[Runs with Oracle JDeveloper 11.1.2.0.0 (11g R2) + HR Schema]

Implementation Steps

Create Fusion Web Application with entity based on Departments, then create a stateless session bean and add the below method. Expose the method to local/remote interface and generate data control.

Note:- Here in the below code "em" is a EntityManager.

/**
 * Here param deptList will be having the selected key row with modified data.
 * Iterating through the deptList and find the depratments object instance by primary key
 * Merge the data using merge api
 * @param deptList
 */ 
public void updateMultipleDeptRows(List deptList) {
 if (deptList.size() > 0) {
  Iterator iIter = deptList.iterator();
  while (iIter.hasNext()) {
   HashMap map = (HashMap)iIter.next();
   //Finding the departments object instance
   Departments departments = em.find(Departments.class, map.get("departmentId"));
   departments.setDepartmentName((String)map.get("departmentName"));
   departments.setLocationId((BigDecimal)map.get("locationId"));
   em.merge(departments);
  }
 }
}    

Create index.jspx page and drag and drop departmentsFindAll->Table as ADF Table. and create the backingBean as "IndexBean". Surround the table with panel collection, add the toolbar, drop button inside toolbar and name as "Save".

Bind the departments table to the backing bean as show below.


Create the ActionListener method called "updateMultipleRows" for save button.


Open the IndexBean backing bean and add the below code.

public void updateMultipleRows(ActionEvent actionEvent) {
 RowKeySet selectedDepts = getDeptTable().getSelectedRowKeys();
 Iterator selectedDeptIter = selectedDepts.iterator();
 DCBindingContainer bindings = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
 DCIteratorBinding deptIter = bindings.findIteratorBinding("departmentsFindAllIterator");
 RowSetIterator deptRSIter = deptIter.getRowSetIterator();
 List deptList = new ArrayList();
 while (selectedDeptIter.hasNext()) {
  Key key = (Key)((List)selectedDeptIter.next()).get(0);
  Row currentRow = deptRSIter.getRow(key);
  HashMap rowValues = new HashMap();
  rowValues.put("departmentId", currentRow.getAttribute("departmentId"));
  rowValues.put("departmentName", currentRow.getAttribute("departmentName"));
  rowValues.put("locationId", currentRow.getAttribute("locationId"));
  deptList.add(rowValues);
 }
 //Execute the updateMultipleDeptRows method by passing deptList param
 OperationBinding oper = bindings.getOperationBinding("updateMultipleDeptRows");
 oper.getParamsMap().put("deptList", deptList);
 oper.execute();
 //Refresh the table
 AdfFacesContext.getCurrentInstance().addPartialTarget(this.getDeptTable());
}    

Go to Bindings tab in index.jspx page and add updateMultipleDeptRows method action.


Run the index.jspx page, select the multiple rows and change the values respectively. Now click on save button should merge the multiple records to the database.

Thursday, May 3, 2012

Implement Tree/Details With Taskflow Regions Using EJB DataControl

Let us take scenario where we need to display Tree/Details, left region contains category hierarchy with items listed in a tree structure (ex:- Region-Countries-Locations-Departments in tree format) and right region contains the Employees list.

In detail, Here User may drills down through categories using a tree until Employees are listed. Clicking the tree node name displays Employee list in the adjacent pane related to particular tree node. This article describes on Display Tree/Details using taskflow regions.

Read complete article

Tuesday, May 1, 2012

EJB Named Criteria - Apply bind variable in Backingbean

EJB Named criteria are predefined and reusable where-clause definitions that are dynamically applied to a ViewObject query. Here we often use to filter the ViewObject SQL statement query based on Where Clause conditions.

Take a scenario where we need to filter the SQL statements query based on Where Clause conditions, instead of playing with SQL statements use the EJB Named Criteria which is supported by default in ADF and set the Bind Variable parameter at run time.

You can download the sample workspace from here
[Runs with Oracle JDeveloper 11.1.2.0.0 (11g R2) + HR Schema]

Implementation Steps

Create Fusion Web Application with entity based on Employees table, then create a session bean and data control for the session bean.

Open the DataControls.dcx file and create sparse xml for as shown below.


In sparse xml navigate to Named criteria tab -> Bind Variable section, create binding variable deptId.


Now create a named criteria and map the query attributes to the bind variable.


In the ViewController create index.jspx page, from data control palette drop employeesFindAll->Named Criteria->EmployeesCriteria->Table as ADF Read-Only Filtered Table and create the backingBean as "IndexBean".

Open the index.jspx page and remove the "filterModel" binding from the table, add <af:inputText />, command button and bind them to backingBean. For command button create the actionListener as "applyEmpCriteria" and add below code to the file.

public void applyEmpCriteria(ActionEvent actionEvent) {
   DCIteratorBinding dc = (DCIteratorBinding)evaluteEL("#{bindings.employeesFindAllIterator}");
   ViewObject vo = dc.getViewObject();
   vo.applyViewCriteria(vo.getViewCriteriaManager().getViewCriteria("EmployeesCriteria"));
   vo.ensureVariableManager().setVariableValue("deptId", this.getDeptId().getValue());
   vo.executeQuery();
}

/**
 * Programmtic evaluation of EL
 *
 * @param el EL to evalaute
 * @return Result of the evalutaion
 */
public Object evaluteEL(String el) {
 FacesContext fctx = FacesContext.getCurrentInstance();
 ELContext elContext = fctx.getELContext();
 Application app = fctx.getApplication();
 ExpressionFactory expFactory = app.getExpressionFactory();
 ValueExpression valExp = expFactory.createValueExpression(elContext, el, Object.class);
 return valExp.getValue(elContext);
}
Run the index.jspx page, enter departmentId value as 90 and click in ApplyEmpCriteria button. Now the bind variable for the Named criteria will be applied at runtime in the backing bean and it will re-execute ViewObject query to filter based on where clause condition.