Thursday, January 31, 2013

Accessing the ADF Binding Layer from Java

BindingContext and BindingContainer

BindingContext is a container object that holds a list of available data controls and data binding objects. It is the Java representation of all cpx files marked in your adfm.xml file. Whereas the BindingContainer class represents Java representation of the page definition file.
   import oracle.adf.model.BindingContext;
   import oracle.binding.BindingContainer;
   ...
   ...
    public BindingContainer getBindings() {
        return BindingContext.getCurrent().getCurrentBindingsEntry();
    }

The DCBindingContainer class exposes more methods than are defined by the BindingContainer interface.
import oracle.adf.model.binding.DCBindingContainer;
...
DCBindingContainer bindings = (DCBindingContainer)this.getBindings();

DCIteratorBinding

It is used to access the rowset iterator of a view object.
import oracle.adf.model.binding.DCIteratorBinding;
import oracle.jbo.Row;
...
DCBindingContainer bc = (DCBindingContainer) getBindings();
DCIteratorBinding iteratorBinding = bc.findIteratorBinding("DepartmentsIterator");
//Execute VO query by executing iterator
iteratorBinding.executeQuery();
//To gets the underlying view object for the iterator
//ViewObject vo = iteratorBinding.getViewObject();
Row currentRow = iteratorBinding.getCurrentRow();

OperationBinding

import oracle.binding.OperationBinding;
...
...
    public void updateDepartmentRow(Row currentDeptRow) {
        BindingContainer bindings = getBindings();
        OperationBinding operationBinding = bindings.getOperationBinding("updateDepartments");
        operationBinding.getParamsMap().put("deptRow", currentDeptRow);
        Object returnValue = operationBinding.execute();
        if (operationBinding.getErrors().isEmpty()) {
            //No exception, Operation is success
        } else {
            //Exception is thrown from the method, handle it here
            //OperationBinding::getErrors() return list of JboException
            List errorList = operationBinding.getErrors();
            //Alternative path 'on error' go here
        }
    }

AttributeBinding

import oracle.binding.AttributeBinding;
...
...
AttributeBinding departmentName = (AttributeBinding) bindings.get("DepartmentName");

JUCtrlListBinding

To access the list binding from Java, you use the JUCtrlListBinding class, as shown next:
   import oracle.jbo.uicli.binding.JUCtrlListBinding;
   import oracle.jbo.domain.Number;
   ...
   JUCtrlListBinding listBinding = (JUCtrlListBinding) bindings.get("JobId");
   ViewRowImpl selectedListRow = (ViewRowImpl) listBinding.getSelectedValue();
   String jobIdValue = (String) selectedListRow.getAttribute("JobId");
   Number maxSalary = (Number) selectedListRow.getAttribute("MaxSalary");

JUCtrlHierBinding

The JUCtrlHierBinding class is used to bind tree, treetable, and table components to the ADF model.
JUCtrlHierBinding hierBinding = (JUCtrlHierBinding)bindings.get("EmployeesView3");

Access Parameter Binding

import oracle.adf.model.binding.DCBindingContainer;
...
...
    public String getPageParamater() {
        DCBindingContainer bindings = (DCBindingContainer)this.getBindings();
        Map map = bindings.getParametersMap();
        String name = map.get("name").toString();
        return null;
    }

Friday, January 25, 2013

EO Code Snippets for ADF

Creating an entity instance

    public DepartmentEOImpl createDeptEntity() {
        //Find the entity definition from the implementation class
        EntityDefImpl departmentEODef = DepartmentEOImpl.getDefinitionObject();
        //Create the blank entity instance
        DepartmentEOImpl newDept = (DepartmentEOImpl)departmentEODef.createInstance2(this.getDBTransaction(), null);
        newDept.setDepartmentId(1000);
        try {
            getDBTransaction().commit();
        } catch (JboException ex) {
            getDBTransaction().rollback();
            throw ex;
        }
        return newDept;
    }

Find and update an entity row

    public void findAndUpdateDeptEntity(Integer deptId) {
        //Create Key
        Key key = DepartmentEOImpl.createPrimaryKey(deptId);
        //Find the entity row
        DepartmentEOImpl deptRow =
            (DepartmentEOImpl)DepartmentEOImpl.getDefinitionObject().findByPrimaryKey(getDBTransaction(), key);
        deptRow.setDepartmentName("IT Admin");
    }

Remove an entity row

    public void findAndRemoveDeptEntity(Integer deptId) {
        Key key = DepartmentEOImpl.createPrimaryKey(deptId);
        DepartmentEOImpl deptRow = (DepartmentEOImpl)DepartmentEOImpl.getDefinitionObject().findByPrimaryKey(getDBTransaction(), key);
        deptRow.remove();
    }

Find the entity object by using primary key

    private DepartmentEOImpl findDepartmentById(int deptId) {
        //Find the entity definition from the implementation class
        EntityDefImpl departmentEODef = DepartmentEOImpl.getDefinitionObject();
        //Create the Key object
        Key orderKey = DepartmentEOImpl.createPrimaryKey(new Integer(deptId));
        //Find and return the desired instance
        return (DepartmentEOImpl)departmentEODef.findByPrimaryKey(getDBTransaction(), orderKey);
    }

To programmatically access the destination entities using the association accessor generated on entity implementation class

    private DepartmentEOImpl findDepartmentById(int deptId) {
        EntityDefImpl deptEODef = DepartmentEOImpl.getDefinitionObject();
        //Find Creates the Key to find Department
        Key deptIdKey = DepartmentEOImpl.createPrimaryKey(new Integer(deptId));
        //Find the Department entity using deptId
        DepartmentEOImpl deptEOImpl = (DepartmentEOImpl)deptEODef.findByPrimaryKey(getDBTransaction(), deptIdKey);
        //Access Employees for this departament using association accessor getEmpEO() generated on DepartmentEOImpl class
        RowIterator rowIter = DepartmentEOImpl.getEmpEO();
        while (rowIter.hasNext()) {
            Row row = rowIter.next();
            //Row represent Emp entity instance
            //Business logic goes here
        }
    }

Thursday, January 24, 2013

Breadcrumb Navigation in ADF Page

OKAY. So this is based on Region-Country-Location tables of the HR schema. This is the opening page.
User selects 'Americas' from the table displayed above. List of the countries are displayed like below:
Finally user selects 'United States of America' from the table displayed above. This is the final result.

Do notice the breadcrumb navigation as we go deeper into the tables. As there is no dedicated button displayed on the table in order to go to the main table, user can click on 'Main' link displayed on top.

In this sample, we have defined 2 parameters: p_RegionId and p_CountryId.


Now these pageFlowScope variables need to be set when the user clicks on a link in the table. Say like the user selects Americas from the Regions table. So the value #{row.RegionId} needs to be fetched into #{pageFlowScope.RegionId} which is binded with p_RegionId parameter defined in the page. For this we have defined 'Set Action Listener'.
Similarly, for Countries table,
When the user clicks on 'Main' of the breadcrumb navigation,
When the user clicks on Region Name link of the breadcrumb navigation,

This is the method defined in AM. The method is accepting 2 parameters:
1. RegionId: Fetched when the user clicks on any Region
2. CountryId: Fetched when the user clicks on any Country

This method is called on page load. For this, we have to create an executable of type invokeAction, binding the method and then moving to the top position in the executable section.
Also check the Rendered property of the different navigation items and the tables. 

Download the sample application from File Cabinet: RegionCountryLocation.rar

Display Employees Based on Department ID

User will enter a department ID in the input text component, and then press Tab key. Employees corresponding to that department ID will be displayed. The slider will move representing the number of employees in that department.


Properties of the input text component:
(Appearence) ShowRequired: True
AutoSubmit: True
ValueChangeListener: #{test.displayTable}
(Behaviour) Required: True


This is the method defined in the managed bean:


private RichInputNumberSlider slider;
 
public void displayTable(ValueChangeEvent valueChangeEvent) {
 
    Integer getValue = null;
 
    try {
        //Validating integer. If it is a string, else it will go into exception
        getValue = Integer.valueOf(valueChangeEvent.getNewValue().toString());
 
        BindingContext bctx = BindingContext.getCurrent();
        BindingContainer bindings = bctx.getCurrentBindingsEntry();
        OperationBinding method = (OperationBinding)bindings.get("displayEmployeeTable");
        method.getParamsMap().put("deptId", getValue);
 
        Object retValue = method.execute();
        slider.setValue(retValue);
        //setSlider(retValue);
        AdfFacesContextImpl.getCurrentInstance().addPartialTarget(slider);
    } catch (Exception e) {
        //Display message on the screen. '"it1' is the id of the inputtext component
        FacesContext fctx = FacesContext.getCurrentInstance();
        fctx.addMessage("it1", new FacesMessage(FacesMessage.SEVERITY_ERROR, "Enter a Valid Department ID", null));
    }
}


Now imagine there is no input text component, and we want to show it as an LOV. In that case we can use the code below to fetch the value from LOV:

    public void displayNumber(ValueChangeEvent valueChangeEvent) {
        BindingContext bctx = BindingContext.getCurrent();
        BindingContainer bindings = bctx.getCurrentBindingsEntry();

        /*The DepartmentId is a choice list and its default binding gives you the position of the selected value in the list, not the value. So create an attribute
value named DepartmentIdValue. This could have been done rather than using JUCtrlListBinding.
        AttributeBinding attr = (AttributeBinding)bindings.getControlBinding("DepartmentIdValue");
        Number selectedValue = (Integer)attr.getInputValue();
        System.out.println("selectedValue: " + selectedValue);*/
        
        //The class below does the exact job what we want
        JUCtrlListBinding list = (JUCtrlListBinding) bindings.get("DepartmentId");  
        Number selectedValue = (Number) list.getAttributeValue();
        System.out.println("selectedValue: " + selectedValue);

        OperationBinding method = (OperationBinding)bindings.get("displayNumberEmployees");
        ...
        ...
    }

Here we are defining a view criteria programatically in AM

    public Number displayEmployeeTable(Integer deptId) {
        ViewObjectImpl vo = getEmployees1();
        ViewCriteria vc = vo.createViewCriteria();
        ViewCriteriaRow vcr1 = vc.createViewCriteriaRow();
        vcr1.setAttribute("DepartmentId", +deptId);
        vc.add(vcr1);
        vo.applyViewCriteria(vc);
        System.out.println("Query: " + vo.getQuery());
        vo.executeQuery();
        return vo.getEstimatedRowCount();
    }
TIP: In case we have to disable the view criteria that we have created programatically, then use the below code:

vo.applyViewCriteria(null);
vo.executeQuery();
In case we had thought of appending a where clause at runtime instead of view criteria, then

    public Number displayEmployeeTable(Integer deptId) {
        ViewObjectImpl vo = getEmployees1();
        vo.setWhereClause("EmployeesEO.DEPARTMENT_ID = :bindVarDeptId");
        vo.defineNamedWhereClauseParam("bindVarDeptId", null, null);
        vo.setNamedWhereClauseParam("bindVarDeptId", deptId);
        vo.executeQuery();
        return vo.getEstimatedRowCount();
    }
Download the sample application from File Cabinet: DispEmployeesBasedDeptId.rar