Thursday, December 5, 2013

RIDC: GET_DATARESULTSET Service to get the list of docTypes

To achieve the above requirement we would need to use GET_DATARESULTSET service which by definition executes a Select query against the database.

Required parameter for this service is "dataSource" which is a preset query present in std_resources.htm (location : <mw_home>/Oracle_ECM1/ucm/idc/resources/core/tables) under <@table DataSources@>.



package client;

import oracle.stellent.ridc.IdcClient;
import oracle.stellent.ridc.IdcClientException;
import oracle.stellent.ridc.IdcClientManager;
import oracle.stellent.ridc.IdcContext;
import oracle.stellent.ridc.model.DataBinder;
import oracle.stellent.ridc.model.DataObject;
import oracle.stellent.ridc.model.DataResultSet;
import oracle.stellent.ridc.protocol.ServiceResponse;


public class RIDCDocTypes {
    
    private static final String WHERE_CLAUSE = null;
    private static final String ORDER_CLAUSE = " order by DocTypes.dDocType desc";

    public static void main(String[] args) {
        IdcClientManager manager = new IdcClientManager();
        try {
            IdcClient idcClient = manager.createClient("idc://127.0.0.1:4444");
            IdcContext userContext = new IdcContext("sysadmin");

            //HdaBinderSerializer serializer = new HdaBinderSerializer("UTF-8", idcClient.getDataFactory());

            DataBinder serviceBinder = idcClient.createBinder();
            serviceBinder.putLocal("IdcService", "GET_DATARESULTSET");
            serviceBinder.putLocal("dataSource", "DocTypes");
            serviceBinder.putLocal("resultName", "DocTypesList");
            
            if (WHERE_CLAUSE != null) {
                    serviceBinder.putLocal("whereClause", WHERE_CLAUSE);
            }

            if (ORDER_CLAUSE != null) {
                    serviceBinder.putLocal("orderClause", ORDER_CLAUSE);
            }

            //serializer.serializeBinder(System.out, dataBinder);
            ServiceResponse response = idcClient.sendRequest(userContext, serviceBinder);
            DataBinder responseData = response.getResponseAsBinder();
            //serializer.serializeBinder(System.out, responseData);

            DataResultSet resultSet = responseData.getResultSet("DocTypesList");

            for (DataObject dataObject : resultSet.getRows()) {
                System.out.println(dataObject.get("dDocType"));
            }

        } catch (IdcClientException ice) {
            ice.printStackTrace();
        } /*catch (IOException ioe) {
            ioe.printStackTrace();
        }*/
    }
}

Similarly, we can get the list of all documents, users, workflows, revisions, etc. This service can be used from browser as well in the following manner : 

http://hostname:port/cs/idcplg?IdcService=GET_DATARESULTSET&dataSource=DocTypes&resultName=DocTypesList&IsJava=1

UCM: Oracle WebCenter Content Server Startup


The startup process contains five steps and takes place in two locations: Oracle WebLogic Server (step 1) and Oracle WebCenter Content Server (steps 2–5). Important Content Server files are as follows:

• intradoc.cfg
   - The intradoc.cfg file is a configuration file that contains the settings for Content Server services, applets, and utilities.
   - It is used to define system variables for Content Server, including directory, Internet and refinery settings, as well as server services, applets, and utilities.
   - Some variables can be set using Content Server’s System Properties utility.
   - <IntradocDir>/bin

• config.cfg
   - The config.cfg file defines the system configuration variables.
   - It is used to define global variables and configuration settings for Content Server.
   - Many of these variables can be set using Content Server’s System Properties utility or the Admin Server’s General Configuration page.
   - <IntradocDir>/config

• idccs_components.hda
   - The idccs_components.hda file identifies all installed custom components that have been added to the Content Server system.
   - This is the file that is read last in step 4 of the startup process.
   - If no custom components are enabled in the system, this file will not have any entries. In this case, the Content Server startup is complete after step 4, and step 5 is obsolete.
   - Step 5 is executed only if one or more custom components are enabled.
   - <IntradocDir>/data/components
<IntradocDir>: C:\Oracle\Middleware\user_projects\domains\base_domain\ucm\cs

Tuesday, September 17, 2013

Programmatically Accessing ADF Security Context to Obtain Information About Users and Roles

Is ADF security turned on?
if (ADFContext.getCurrent().getSecurityContext().isAuthorizationEnabled())
{
  ...
}

Is the user logged on?
public boolean isAuthenticated() {
  return ADFContext.getCurrent().getSecurityContext().isAuthenticated();
}

Who is the user?
public String getCurrentUser() {
  return ADFContext.getCurrent().getSecurityContext().getUserName();
}

Is the user in a specified role?
public boolean isUserInRole(String role) {
  return ADFContext.getCurrent().getSecurityContext().isUserInRole(role);
}

Thursday, August 8, 2013

Oracle ADF Tutorials

Developing Applications with ADF Mobile

For anyone looking to learn the technologies behind Oracle's strategic mobile development initiative, they have just launched a new interactive on-line learning aid.

http://bit.ly/ADFMobileCourse
OR
http://download.oracle.com/otn_hosted_doc/jdeveloper/academy/Developing%20Applications%20with%20ADF%20Mobile/player.html

ADF Academy brings interactive learning to your desktop and this first release of ADF Academy focuses on ADF Mobile. Learn from Oracle experts, watch demos, takes quizzes and become and iOS and Andoird developer in one day!


Advanced ADF eCourse Module Part I and II by Oracle

It is one in a wider series of modules which address topics that are useful for the experienced ADF developer.

Part I: http://download.oracle.com/tutorials/jtcd3/ecourse_adf_part1/html/temp_frameset/index.htm

Part II: http://download.oracle.com/tutorials/jtcd3/ecourse_adf_part2/html/temp_frameset/index.htm

Thursday, August 1, 2013

ADF - Prevent Iterator to Execute on Pageload

You just need to set the Refresh and RefreshConditions as shown in the screenshot below:


Refresh: ifNeeded
RefreshCondition: #{requestContext.postback}

Thanks to Ravi for this trick!

Wednesday, July 24, 2013

ADF - Deleting Multi-Selected Rows from table


The user will select multiple records, and then from the menu options, click on Delete Employees for deletion. The user can also click on checkbox at the header level to select all the records in the table.

This is the Java code in the Bean:
package demo.view;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.ValueChangeEvent;

import oracle.adf.model.BindingContext;
import oracle.adf.model.binding.DCBindingContainer;
import oracle.adf.model.binding.DCIteratorBinding;
import oracle.adf.view.rich.event.DialogEvent;
import oracle.adf.view.rich.event.PopupCanceledEvent;
import oracle.adf.view.rich.event.PopupFetchEvent;

import oracle.binding.OperationBinding;

import oracle.jbo.Row;
import oracle.jbo.RowSetIterator;


public class employeeOperations {
    public employeeOperations() {
    }

    public void deleteMultiple(ActionEvent actionEvent) {
        DCBindingContainer bindings = getBindings();
        DCIteratorBinding iteratorBinding = bindings.findIteratorBinding("EmployeeVO1Iterator");

        Row[] r = iteratorBinding.getViewObject().getFilteredRows("SelectBox", true);
        for (int i = 0; i < r.length; i++) {
            r[i].remove();
        }

        OperationBinding operationBinding = bindings.getOperationBinding("Commit");
        operationBinding.execute();
        if (!operationBinding.getErrors().isEmpty()) {
            addFacesMessage(FacesMessage.SEVERITY_ERROR, "Error in Deleting Records");

        } else {
            addFacesMessage(FacesMessage.SEVERITY_INFO, "Records Deleted Succesfully");
        }
    }

    public void dialogListener(DialogEvent dialogEvent) {
        if (dialogEvent.getOutcome().name().equals("ok")) {
            DCBindingContainer bindings = getBindings();
            OperationBinding method = bindings.getOperationBinding("Commit");
            method.execute();
        } else if (dialogEvent.getOutcome().name().equals("cancel")) {
            DCBindingContainer bindings = getBindings();
            OperationBinding method = bindings.getOperationBinding("Rollback");
            method.execute();
        }
        System.out.println("dialogListener Executed");
    }

    public static void addFacesMessage(FacesMessage.Severity severity, String message) {
        FacesMessage fm = new FacesMessage(severity, message, null);
        FacesContext.getCurrentInstance().addMessage(null, fm);
    }

    public DCBindingContainer getBindings() {
        return (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
    }

    public void popupCancelListener(PopupCanceledEvent popupCanceledEvent) {
        DCBindingContainer bindings = getBindings();
        OperationBinding method = bindings.getOperationBinding("Rollback");
        method.execute();
        System.out.println("popupCancelListener Executed");
    }

    public void popupFetchListener(PopupFetchEvent popupFetchEvent) {
        DCBindingContainer bindings = getBindings();
        OperationBinding method = bindings.getOperationBinding("CreateInsert");
        method.execute();
        System.out.println("popupFetchListener Executed");
    }

    public void selectAllRows(ValueChangeEvent valueChangeEvent) {
        DCBindingContainer bindings = getBindings();
        DCIteratorBinding it = bindings.findIteratorBinding("EmployeeVO1Iterator");
        RowSetIterator rit = it.getRowSetIterator();
        //rit.reset();
        if (valueChangeEvent.getNewValue() != null) {
            Boolean selectAll = Boolean.parseBoolean(valueChangeEvent.getNewValue().toString());
            if (rit.first() != null) {
                Row r = rit.first();
                r.setAttribute("SelectBox", selectAll);
            }
            while (rit.hasNext()) {
                Row r = rit.next();
                if (r != null) {
                    r.setAttribute("SelectBox", selectAll);
                }
            }
        }
    }
}

This is the code in the Main.jspx for the checkBox created on the header:
<f:facet name="header">
    <af:selectbooleancheckbox autosubmit="true" id="sbc2" simple="true" valuechangelistener="#{HRBean.selectAllRows}">
</af:selectbooleancheckbox></f:facet>

Download the sample application from File Cabinet: AddDeleteEmployees.rar

Monday, May 20, 2013

ADF: How to use af:popup during long running tasks

Suppose the user wants to upload a file. And once he clicks on Upload button, a popup is displayed which actually disables the user input.

For this, create a javascript file and put it in public_html/js folder. Name the file as glassPane.js. These are the contents of the file:
function enforcePreventUserInput(evt) {
    var popup = AdfPage.PAGE.findComponentByAbsoluteId('popupProcessingChanges');
    if (popup != null) {
        AdfPage.PAGE.addBusyStateListener(popup, handleBusyState);
        evt.preventUserInput();
    }
}

function handleBusyState(evt) {
    var popup = AdfPage.PAGE.findComponentByAbsoluteId('popupProcessingChanges');
    if (popup != null) {
        if (evt.isBusy()) {
            popup.show();
        }
        else {
            popup.hide();
            AdfPage.PAGE.removeBusyStateListener(popup, handleBusyState);
        }
    }
}

Drop a clientListener component on the button. Set the property 'method' as enforcePreventUserInput, and 'type' as Action.

Now create a popup. Give the id as popupProcessingChanges.
<af:popup contentdelivery="immediate" id="popupProcessingChanges">
        <af:dialog closeiconvisible="false" id="dialogProcessingChanges" title="Processing Changes" type="none">
          <af:panelgrouplayout halign="center" id="pgl1ProcessingChanges" layout="vertical">
            <af:image id="pt_i1" shortdesc="Loading " source="/images/loading.gif">
          </af:image></af:panelgrouplayout>
        </af:dialog>
 </af:popup>

Also drop a resource component on af:form. Give the 'source' as /js/glassPane.js, and 'type' as javascript.

In case you want to use the javascript file in page template, then please refer this link:
http://myjdeveloperhints.blogspot.in/2010/12/add-glass-pane-to-long-running-db-job.html

Monday, May 13, 2013

ADF - Programatically Applying and Creating View Criteria

CASE 1: I have already created a view criteria in EmployeeVO, and I want to call it programmatically.
    public void searchEmployee(Number employeeId) {
        ViewObjectImpl vo = getEmployeesView1();
        ViewCriteria vc = vo.getViewCriteria("findEmployeeVC");
        vo.applyViewCriteria(vc);
        vo.setNamedWhereClauseParam("pEmployeeId", employeeId);
        vo.executeQuery();
    }

CASE 2: I want to create a view criteria dynamically and execute it programmatically.
    public void searchByEmployeeIdEmail(Number employeeId, String email) {
        ViewObjectImpl vo = getEmployeesView2();
        ViewCriteria vc = vo.createViewCriteria();
        ViewCriteriaRow vcRow = vc.createViewCriteriaRow();
        
        vcRow.setAttribute("EmployeeId", employeeId);
        vc.addRow(vcRow);
        vcRow.setAttribute("Email", email);
        vc.addRow(vcRow);
        
        vo.applyViewCriteria(vc);
        vo.executeQuery();
    }

Thursday, May 9, 2013

ADF - Populate ADF Table using managed Bean and DTO


In this use case, we will be building an employee form where the user will enter details and then click on Save. Once the data is saved, the results will be displayed in the table below.


For every field displayed on the form, we need to declare a variable in the managed bean, and create getters setters.
    private String firstName;
    private String lastName;
    private String email;
    private Date hireDate;
    private String jobID;

Now for every inputField, bind the value property with the variable defined. For example, for the First Name field, I have set the value property as #{pageFlowScope.myBean.firstName}.

This is the method defined in the managed bean for the Save button:
    public void onClickSave(ActionEvent actionEvent) {
        // Add event code here...
        Map searchValueMap = new HashMap();
        searchValueMap.put(FIRST_NAME, firstName);
        searchValueMap.put(LAST_NAME, lastName);
        searchValueMap.put(EMAIL, email);
        searchValueMap.put(HIRE_DATE, hireDate);
        searchValueMap.put(JOB_ID, jobID);

        Map parameters = new HashMap();
        parameters.put("params", searchValueMap);

        BindingContainer bindings = getBindings();
        OperationBinding operationBinding =
            bindings.getOperationBinding("saveEmployee");
        operationBinding.getParamsMap().putAll(parameters);
        emplist = (List)operationBinding.execute();

        AdfFacesContext.getCurrentInstance().addPartialTarget(empTable);
    }

This is from the Application module:
    public List saveEmployee(Map params) {
        ViewObjectImpl vo = getEmployeesView1();
        ViewRowImpl vor = (ViewRowImpl)vo.createRow();
        getEmployeesView1().insertRow(vor);
        //vor.setAttribute("EmployeeId", params.get("employeeID"));
        vor.setAttribute("FirstName", params.get("firstName"));
        vor.setAttribute("LastName", params.get("lastName"));
        vor.setAttribute("Email", params.get("email"));
        vor.setAttribute("HireDate", params.get("hireDate"));
        vor.setAttribute("JobId", params.get("jobID"));
        vor.getApplicationModule().getTransaction().commit();

        vo.executeQuery();
        
        List employeeList = null;
        EmployeeDTO employeeDTO = null;
        
        RowSet rowSet = vo.getRowSet();
        Row row = null;
        if (null != rowSet) {
            employeeList = new ArrayList();
            row = rowSet.first();
            while (null != row) {
                employeeDTO = getEmployeeDTOFromRow(row);
                employeeList.add(employeeDTO);
                row = rowSet.next();
            }
        }
        return employeeList;
    }
    
    private EmployeeDTO getEmployeeDTOFromRow(Row row) {
        EmployeeDTO employeeDTO = new EmployeeDTO();
        employeeDTO.setEmployeeID((Number)row.getAttribute("EmployeeId"));
        employeeDTO.setFirstName((String)row.getAttribute("FirstName"));
        employeeDTO.setLastName((String)row.getAttribute("LastName"));
        employeeDTO.setEmail((String)row.getAttribute("Email"));
        employeeDTO.setHireDate((Date)row.getAttribute("HireDate"));
        employeeDTO.setJobID((String)row.getAttribute("JobId"));
        return employeeDTO;
    }

For the table, I have set the value property as #{pageFlowScope.myBean.emplist} and binding property as #{pageFlowScope.myBean.empTable}. Getters and setters are created for both:
    private RichTable empTable;

    private List emplist;

Download the sample application from File Cabinet: ProgrammaticTableDTO.rar

Sunday, March 24, 2013

ADF - Restrict Navigation Based on a Condition

There is a supplier table. If the status of the supplier row is DRAFT, then only will the user be able to see the details of it by clicking on the commandlink.

In this case, set the Action as null, because here we will be setting the navigation manually.

Here we have fetched the value of Status using the propertyListener
From: #{row.Status}
To: #{requestScope.Status}
Type: action

Created a parameter p_status

This is the method that we have defined in the ActionListener property of the commandlink:

    public void moveToDetailPageBasedOnStatus(ActionEvent actionEvent) {
        // Add event code here...
        DCBindingContainer bc = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
        Map map = bc.getParametersMap();
        String status = ((DCParameter)map.get("p_status")).getValue().toString();
        System.out.println("status: " + status);
        if (status.equals("DRAFT")) {
            FacesContext context = FacesContext.getCurrentInstance();
            context.getApplication().getNavigationHandler().handleNavigation(context, null, "create");
        } else {
            FacesContext context = FacesContext.getCurrentInstance();
            FacesMessage message =
                new FacesMessage(FacesMessage.SEVERITY_INFO, "", "User can see the details of an Issue in DRAFT Status only.");
            context.addMessage(null, message);
        }
    }
This is the diagram of the taskflow.
Just remember one point: ActionListener is executed before Action event.

ADF - Setting value of an attribute explicitly

I have a form with 2 buttons, DRAFT and SUBMIT. On click of Draft button, the form will be saved with status attribute as Draft.

    public void onClickSaveDraft(ActionEvent actionEvent) {
        // Add event code here...
        DCBindingContainer bc = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
        DCIteratorBinding iter = bc.findIteratorBinding("IssueVO1Iterator");
        Row r = iter.getCurrentRow();
        r.setAttribute("Status", "DRAFT");

        String issueStatus = (String)r.getAttribute("Status");
        System.out.println("issueStatus: " + issueStatus);

        OperationBinding operationBinding = bc.getOperationBinding("Commit");
        operationBinding.execute();
        if (!operationBinding.getErrors().isEmpty()) {
            System.out.println("Error");
        }
        System.out.println("No Error");
    }

Saturday, March 23, 2013

ADF - Upload Download Functionality

First of all, create a table where the user will be uploading the documents
create table DOCUMENTS
(
  DOCUMENT_ID   NUMBER not null,
  ISSUE_ID      NUMBER,
  DOCUMENT_NAME VARCHAR2(100),
  DOCUMENT_TYPE VARCHAR2(100),
  DOCUMENT_FILE BLOB
)

alter table DOCUMENTS
  add constraint DOCUMENTS_PK primary key (DOCUMENT_ID);

Drop an inputFile component. Bind it with 'inputFile' variable of type RichInputFile. Bind its ValueChangeListener property with onFileUploadVCL method.
    public void onFileUploadVCL(ValueChangeEvent valueChangeEvent) {
        // Add event code here...
        file = (UploadedFile)valueChangeEvent.getNewValue();
        // Get the file name
        fileName = file.getFilename();
        // get the mime type
        contentType = file.getContentType();
        // get blob
        blob = getBlob(file);
    }

    public BlobDomain getBlob(UploadedFile file) {
        InputStream in = null;
        BlobDomain blobDomain = null;
        OutputStream out = null;
        try {
            in = file.getInputStream();
            blobDomain = new BlobDomain();
            out = blobDomain.getBinaryOutputStream();
            IOUtils.copy(in, out);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.fillInStackTrace();
        }
        return blobDomain;
    }

Create 4 variables like this below. Create getter setters for all these variables.
    private String fileName;
    private String contentType;
    private BlobDomain blob;

    private UploadedFile file;

Now drop a button and name it as 'Upload'. Bind this method with this button:
    public void onFileUpload(ActionEvent actionEvent) {
        // Add event code here...

        if (fileName != null) {
            DCBindingContainer bc =
                (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
            OperationBinding operationbinding =
                bc.getOperationBinding("uploadFiletoDB");
            if (operationbinding != null) {
                operationbinding.getParamsMap().put("fileName", fileName);
                operationbinding.getParamsMap().put("contentType",
                                                    contentType);
                operationbinding.getParamsMap().put("blob", blob);
                operationbinding.execute();
            }
            System.out.println("File uploaded successfully");
            if (inputFile != null) {
                inputFile.resetValue();
                inputFile.setValid(true);
            }
        }
    }

This is the method defined in AM:
    public void uploadFiletoDB(String fileName, String contentType,
                               BlobDomain blob) {
        ViewObjectImpl vo = this.getDocumentsView1();
        try {
            Row row = vo.createRow();
            row.setAttribute("DocumentName", fileName);
            row.setAttribute("DocumentType", contentType);
            row.setAttribute("DocumentFile", blob);
            vo.insertRow(row);
        } catch (Exception e) {
            e.printStackTrace();
        }
        this.getDBTransaction().commit();
    }

In order to download the file uploaded, drop a fileDownloadActionListener component with the following properties. Also create attribute bindings for the same:
ContentType: #{bindings.DocumentType.inputValue}
FileName: #{bindings.DocumentName.inputValue}
Method: #{myBean.downloadFile}

    public void downloadFile(FacesContext facesContext,
                             OutputStream outputStream) {
        // Add event code here...
        DCBindingContainer bindings =
            (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
        DCIteratorBinding iteratorbinding =
            bindings.findIteratorBinding("DocumentsView1Iterator");
        BlobDomain blob =
            (BlobDomain)iteratorbinding.getCurrentRow().getAttribute("DocumentFile");
        try {
            IOUtils.copy(blob.getInputStream(), outputStream);
            blob.closeInputStream();
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

In order to set larger maximum file size setting, add following parameter into Context Initialization Parameters group of web.xml:
org.apache.myfaces.trinidad.UPLOAD_MAX_DISK_SPACE


This example sets maximum file upload size to 10485760 bytes, or 10MB

Creation of a row in different tables with a single button click


I have a Create button, and below that 2 tables namely Order and Order_Item. I have created a composition association, and a view link. How can I perform creation of rows in both tables with a single click of Create button?

In order to implement this, create a composition association between the EOs. Then create a method in AM

    public void createItem() {
        ViewRowImpl vor1 = (ViewRowImpl)getOrderVO1().createRow();
        ViewRowImpl vor2 = (ViewRowImpl)getOrderItemVO2().createRow();
        getOrderVO1().insertRow(vor1);
        getOrderItemVO2().insertRow(vor2);
    }
Then create the binding of this method in the ActionListener property of the command button.

    public void createIssue(ActionEvent actionEvent) {
        // Add event code here...
        DCBindingContainer bc = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
        OperationBinding method = bc.getOperationBinding("createItem");
        method.execute();
    }



Monday, March 4, 2013

ADF: Traversing Associations


JDeveloper generates accessor methods for each association:
  1. a getter and a setter in the destination to retrieve the source
  2. a getter in the source to get the destination.
To delete all of the child entity rows in an entity association relation.

    public void remove() {
        // get the department employeess accessor
        RowIterator deptEmployees = getEmployeeEO();
        // iterate over all department employees
        while (deptEmployees.hasNext()) {
            // get the department employee
            EmployeeEOImpl deptEmployee = (EmployeeEOImpl)deptEmployees.next();
            // remove employee
            deptEmployee.remove();
        }
        super.remove();
    }

To delete a department when the last department employee is deleted.

    public void remove() {
        DepartmentEOImpl department = getDepartmentEO();
        int numberOfEmp = department.getEmployeeEO().getRowCount();
        // check whether last employee in the department
        if (numberOfEmp == 1) {
            // delete the last employee
            super.remove();
            // delete the department as well
            department.remove();
        } else {
            // just delete the employee
            super.remove();
        }
    }    

Friday, February 22, 2013

Restrict rows in a table (ADF Table Pagination)

So the user will select a department from the navigation list, and the employees will be displayed in group of N. User can click on the buttons below to traverse through the table.

You need to be aware of some of the properties of a table.


  1. AutoHeightRows: By defining this attribute, the table height is adjusted according to the content. The fetchSize and autoHeightRows attributes together control the number of rows displayed in the table. Please note that the value of the autoHeightRows attribute cannot exceed the value set for the fetchSize attribute.
  2. RangeSize: It controls the number of transactions that are required to populate the table as the user scrolls up and down.


This is the code for the af:table:

autoheightrows="5" contentdelivery="immediate" emptytext="#{bindings.EmployeesView3.viewable ? 'No data to display.' : 'Access Denied.'}" fetchsize="#{bindings.EmployeesView3.rangeSize}" id="t1" partialtriggers="::cb1 ::cb2 ::cb3 ::cb4" rowbandinginterval="0" rows="#{bindings.EmployeesView3.rangeSize}" rowselection="single" selectedrowkeys="#{bindings.EmployeesView3.collectionModel.selectedRow}" selectionlistener="#{PagingBean.rowSelected}" value="#{bindings.EmployeesView3.rangeSet}" var="row" width="100%"

This is the code in the bean:
package view;

import oracle.adf.model.BindingContext;
import oracle.adf.share.logging.ADFLogger;

import oracle.binding.BindingContainer;

import oracle.jbo.uicli.binding.JUCtrlRangeBinding;

import org.apache.myfaces.trinidad.event.SelectionEvent;

public class PagingBean {

    private int pageNumber;
    private static final int RANGE_SIZE = 5;
    private static ADFLogger _logger = ADFLogger.createADFLogger(PagingBean.class);

    /**
     * Invoked when user select a row in the table.
     * @param se
     */
    public void rowSelected(SelectionEvent se) {
        JUCtrlRangeBinding staffView = getEmployeeView();
        staffView.getIteratorBinding().setCurrentRowIndexInRange((Integer)se.getAddedSet().toArray()[0]);
    }

    /**
     * Invoked when user click the Go button to go to the target page
     * @return
     */
    public String goToPage() {
        JUCtrlRangeBinding staffView = getEmployeeView();
        int prePage = staffView.getIteratorBinding().getNavigatableRowIterator().getRangeStart() / RANGE_SIZE + 1;
        _logger.info("prePage: " + prePage);
        staffView.getIteratorBinding().getNavigatableRowIterator().scrollRange(RANGE_SIZE *
                                                                               (this.pageNumber - prePage));
        return null;
    }

    /**
     * Invoked when user click to go to the last page
     * @return
     */
    public String goLastPage() {
        JUCtrlRangeBinding staffView = this.getEmployeeView();
        long lastPageNum = Math.max(1, (staffView.getIteratorBinding().getEstimatedRowCount() - 1) / RANGE_SIZE + 1);
        _logger.info("lastPageNum: " + lastPageNum);
        if (lastPageNum <= 1)
            return null;
        int prePage = staffView.getIteratorBinding().getNavigatableRowIterator().getRangeStart() / RANGE_SIZE + 1;
        _logger.info("prePage: " + prePage);
        staffView.getIteratorBinding().getNavigatableRowIterator().scrollRange((int)(RANGE_SIZE *
                                                                                     (lastPageNum - prePage)));
        return null;
    }

    /**
     * Is go to last button enabled
     * @return
     */
    public boolean isLastEnabled() {
        JUCtrlRangeBinding staffView = this.getEmployeeView();
        long lastPageNum = Math.max(1, (staffView.getIteratorBinding().getEstimatedRowCount() - 1) / RANGE_SIZE + 1);
        _logger.info("lastPageNum: " + lastPageNum);
        long currentPage = staffView.getIteratorBinding().getNavigatableRowIterator().getRangeStart() / RANGE_SIZE + 1;
        _logger.info("currentPage: " + currentPage);
        _logger.info("Boolean" + (currentPage < lastPageNum));
        return currentPage < lastPageNum;
    }

    public void setPageNumber(int pageNumber) {
        _logger.info("pageNumber: " + pageNumber);
        this.pageNumber = pageNumber;
    }

    public int getPageNumber() {
        int i = getEmployeeView().getIteratorBinding().getNavigatableRowIterator().getRangeStart() / RANGE_SIZE + 1;
        _logger.info("i: " + i);
        return pageNumber =
                getEmployeeView().getIteratorBinding().getNavigatableRowIterator().getRangeStart() / RANGE_SIZE + 1;
    }

    private JUCtrlRangeBinding getEmployeeView() {
        BindingContext bindingCtx = BindingContext.getCurrent();
        BindingContainer bindings = bindingCtx.getCurrentBindingsEntry();
        return (JUCtrlRangeBinding)bindings.getControlBinding("EmployeesView3");
    }
}

Download the sample application from File Cabinet: TablePagination.rar

Thursday, February 21, 2013

ADF Logger (ADFLogger)

As per Duncan, install the logging template in JDeveloper. To install these:
  1. Open  Tools --> Preferences from the JDeveloper menu
  2. Expand the Code Editor --> Code Templates node in the preferences navigator
  3. Select the More Actions --> Import menu option as shown here and import the loggingTemplates.xml file from the File Cabinet.

Now say you have defined a class while developing an application in ADF. So inside the class, type 'lgdef' and press Ctrl+Enter. This will create a logging object automatically with the name _logger.
private static ADFLogger _logger = ADFLogger.createADFLogger(BCPagingMB.class);
In the above example, BCPagingMB is the name of the class.

Now wherever you were using sop statement, type 'lgi', press Ctrl+Enter, enter the message that you want to display.

Then in the IntegratedWebLogicServer Log, click on Actions and go to Configure Oracle Diagnostic Logging. Now I had written the code in the view package. So search for view in the RootLogger tree. Select it. Click the plus button to add a Transient Logger. Enter the Logger name as the name of the package (in this case, view), and set the logger level as Info.

You can read more about ADFLogger in Duncan Mills's blog.

Wednesday, February 20, 2013

Different ways of setting Sequence Number in ADF

1. In EmployeesEO, change the type of EmployeeID to be Number, Default Value to be Expression, and set the value as
(new oracle.jbo.server.SequenceImpl("HR.EMPLOYEES_SEQ", adf.object.getDBTransaction())).getSequenceNumber()

2. Override the create() in EmployeesEOImpl class as follows:
    protected void create(AttributeList attributeList) {
        super.create(attributeList);
        SequenceImpl seq = new SequenceImpl("EMPLOYEES_SEQ", getDBTransaction());
        Number seqNextval = seq.getSequenceNumber();
        setEmployeeId(seqNextval);
    }

3. Override the initDefaults() in EmployeesEOImpl class as follows:
    protected void initDefaults() {
        super.initDefaults();
        SequenceImpl sequence = new SequenceImpl("EMPLOYEES_SEQ", getDBTransaction());
        DBSequence seqNextval = new DBSequence(sequence.getSequenceNumber());
    }

Saturday, February 16, 2013

'Hello World!' Program for ADF

There will be an inputtext component, the user will click on Submit button, and then output will be displayed below the button.

A managed bean should be created for each of the inputtext and outputtext components so that we can access the value. This is the code created in the managed bean:

public class test {
    private RichInputText input;
    private RichOutputText output;

    public test() {
    }

    public String cb1_action() {
        // Add event code here...
        String test_input = (String)input.getValue();
        System.out.println("value: "+test_input);
        String value = "Hello " +test_input+ "!!";
        output.setValue(value);
        return null;
    }

    public void setInput(RichInputText input) {
        this.input = input;
    }

    public RichInputText getInput() {
        return input;
    }

    public void setOutput(RichOutputText output) {
        this.output = output;
    }

    public RichOutputText getOutput() {
        return output;
    }
}

Now imagine there was no Submit button, and you have to get the result as soon as you press TAB button after entering a string in the inputtext component. In this case, you have to write a method in valueChangeListener property.

    public void displayValue(ValueChangeEvent valueChangeEvent) {
        // Add event code here...
        String test_input = (String)valueChangeEvent.getNewValue();
        System.out.println("value: "+test_input);
        String value = "Hello " +test_input+ "!!";
        output.setValue(value);
    }
Please note that in this case, don't set any method in attributeChangeListener property. Also set the autoSubmit property of inputText component to be True, and the partialTriggers property of the outputtext component to be the inputText component.

Download the sample application from File Cabinet: HelloWorld.rar

Thursday, February 14, 2013

Dependent or Cascading List of Values (LOV) in ADF

I have built this sample on Regions, Countries and Locations table of HR Schema. In addition to it, I have created one more table TEST_RCL. This is the creation script for the same table:

create table TEST_RCL
(
  ID       NUMBER(3),
  REGION   NUMBER(3),
  COUNTRY  VARCHAR2(3),
  LOCATION NUMBER(4)
)
Now the main content. Create a view criteria in CountriesVO where you need to assign attribute RegionID to a bind parameter.

Similarly create a view criteria in LocationsVO too.

Now imagine the actual situation. User should see all the regions in the LOV. Once he/she selects a region, the Countries LOV should display the values related to the region selected in LOV.

So for Country attribute of TestRclVO, create a LOV.
1. Keep the data source to be the CountriesVO.

2. Click on Edit in the View Accessors screen, shuttle the view criteria from the list of available view criterias
3. Set the Value of the regid parameter to be 'Region'.

Follow the related steps for the LocationsVO. And then test the scenario in Model Tester.

Download the sample application from File Cabinet: DependentLOV.rar

Sunday, February 10, 2013

Synchronizing ADF Tree with Table Data

Enabling auto-synchronization between iterators of the same type in a page
Okay. So the user will select the Region and then the Country from tree, and based on the selection, the Locations will be displayed in a table-form structure.

Got the idea from one of the videos of Grant Ronald. Download the sample application from File Cabinet: SyncTableTree.rar

When a tree table is displayed, the framework executes the iterator binding for the top level collection during the initial page load. When you expand a parent node, the framework identifies the accessor attribute for the child nodes from the tree binding definition, and then executes the child view object using the accesor attribute in the parent row.

Saturday, February 9, 2013

Pass Parameters inside an ADF Bounded Taskflow

So there is a 'home' page which is displaying the list of locations. User can either click on the location ID to update the record, or create a location by clicking Create button.

First define an input parameter 'Action' in the 'child' taskflow. Set its value as #{pageFlowScope.Action}.

Drag the CreateInsert operation to the task flow diagram to create a method call activity. Change fixed-outcome of the CreateInsert method call activity to done.

Add an expression to the router: #{pageFlowScope.Action == 'New'}



Now in the 'main' taskflow, click on the 'child' taskflow call and in the Property Inspector, set the value of the parameter as #{requestScope.Action}

Add a setPropertyListener property to the Create button. Set the From property to #{'New'}, To property to #{requestScope.Action} and Type as 'action'.

Download the sample application from File Cabinet: PassParaBoundTskflow.rar


Friday, February 8, 2013

Perform Delete and Commit by a single button click

Create a bean named DeleteCommitBean in UI project.

Add a method named onDeleteItem that calls the ADFUtil.invokeEL() helper method to execute the EL expression that you pass in as a parameter. In this case, it will execute a Delete and a Commit. Note that the Delete and Commit methods must be in the Page Definition Bindings for any page that uses them.
    public void onDeleteItem(ActionEvent actionEvent) {
        ADFUtil.invokeEL("#{bindings.Delete.execute}");
        ADFUtil.invokeEL("#{bindings.Commit.execute}");
        System.out.println("Deleted");
    }
Register the bean as managed bean in adfc-config.xml pageflow file.

In the UI, add a button from the Component Palette. Modify the text as Delete and set the ActionListener as
#{FODCommitDeleteBean.onDeleteItem}
You can also click on 'Edit' to modify the same.

Code snippet of invokeEL method in ADFUtil class
public class ADFUtil {

    public static Object invokeEL(String el) {
        return invokeEL(el, new Class[0], new Object[0]);
    }

    public static Object invokeEL(String el, Class[] paramTypes, Object[] params) {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        ELContext elContext = facesContext.getELContext();
        ExpressionFactory expressionFactory = facesContext.getApplication().getExpressionFactory();
        MethodExpression exp = expressionFactory.createMethodExpression(elContext, el, Object.class, paramTypes);
        return exp.invoke(elContext, params);
    }
}

  • FacesContext is a class that contains all of the per-request state information related to the processing of a single JSF request, and the rendering of the corresponding response. It is passed to, and potentially modified by, each phase of the request processing life cycle.
  • ELContext is a class that is used to evaluate an expression.
  • ExpressionFactory is a class that parses a String into a value expression or a method expression for later evaluation.
For more information about EL Expressions, refer to this post 'ADF UI - ADFUtil class to evaluate, set and invoke EL expressions'

Monday, February 4, 2013

Let's Validate Email ID in ADF

1. Drag an inputText component. Label it as Email. Drop a validate Regular Expression component over it.

validateregexp messagedetailnomatch="Enter a Valid Email ID" pattern="[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}"

2. We will validate the above scenario by calling a PL/SQL function. This is quite interesting.

    public String validateEmail() {
        // Add event code here...
        BindingContainer bindings = getBindings();

        FacesContext facesContext = FacesContext.getCurrentInstance();
        UIViewRoot root = facesContext.getViewRoot();
        RichInputText inputText = (RichInputText)root.findComponent("it6");
        
        String myString = inputText.getValue().toString();
        System.out.println(myString.toString());
        OperationBinding operationBinding = bindings.getOperationBinding("validateEmailByPlsql");
        operationBinding.getParamsMap().put("email", myString);
        Object result = operationBinding.execute();
        System.out.println(result.toString());
        if (result.toString().equals("FAILURE")) {
            FacesContext fctx = FacesContext.getCurrentInstance();
            fctx.addMessage("it6", new FacesMessage(FacesMessage.SEVERITY_ERROR, "Email is not Valid", null));
        } else {
            FacesContext fctx = FacesContext.getCurrentInstance();
            fctx.addMessage("it6", new FacesMessage(FacesMessage.SEVERITY_INFO, "Email Valid", null));
        }
        return null;
    }

    public String validateEmailByPlsql(String email) {
        return (String)callStoredFunction(VARCHAR2, "xx_check_email(?)", new Object[] { email });
    }

    protected Object callStoredFunction(int sqlReturnType, String stmt, Object[] bindVars) {
        CallableStatement st = null;
        try {
            // 1. Create a JDBC CallabledStatement
            st = getDBTransaction().createCallableStatement("begin ? := " + stmt + ";end;", 0);
            // 2. Register the first bind variable for the return value
            st.registerOutParameter(1, sqlReturnType);
            if (bindVars != null) {
                // 3. Loop over values for the bind variables passed in, if any
                for (int z = 0; z < bindVars.length; z++) {
                    // 4. Set the value of user-supplied bind vars in the stmt
                    st.setObject(z + 2, bindVars[z]);
                }
            }
            // 5. Set the value of user-supplied bind vars in the stmt
            st.executeUpdate();
            // 6. Return the value of the first bind variable
            System.out.println(st.getObject(1).toString());
            return st.getObject(1);
        } catch (SQLException e) {
            throw new JboException(e);
        } finally {
            if (st != null) {
                try {
                    // 7. Close the statement
                    st.close();
                } catch (SQLException e) {
                }
            }
        }
    }

Now define a function 'xx_check_email' in your database which will be taking one String parameter and validate whether the String is a proper email ID or not.

For more details, check the section Invoking Stored Procedure and Functions from Developer's Guide: http://docs.oracle.com/cd/E24382_01/web.1112/e16182/bcadvgen.htm#insertedID6

Now suppose we have an employee record and while creating it, we have to supply the emailID. Then we will press Commit button. In this case I am showing you 2 ways to validate the same.

1. Create a validation rule on email attribute. Set the rule type as Method, with a proper error message in Failure Handling tab. A method will be generated in EntityImpl class
    public boolean validateEmail(String email) {
        int atpos = email.indexOf('@');
        int dotpos = email.lastIndexOf('.');
        if (atpos == -1 || dotpos == -1) {
            return false;
        }
        return true;
    }
2. Domain: I am having some problem while validating the same with domains. I am getting this error message: 'Cannot convert testmailid of type class java.lang.String to class model.common.DomainEmail'.

3. We can validate in the setter method of email.
    public void setEmail(String value) {

        int atpos = value.indexOf('@');
        int dotpos = value.lastIndexOf('.');
        if (atpos == -1 || dotpos == -1) {
            throw new oracle.jbo.JboException("Invalid Email ID");
        }
        setAttributeInternal(EMAIL, value);
    }

Saturday, February 2, 2013

Lifecycle of an Entity Object in ADF


This is an extract taken from book Oracle ADF Real World Developer's Guide.

When you create an instance of an entity object by using the createInstance2(DBTransaction, AttributeList) method on the entity definition, its state is New. Entity objects in the New state will qualify in order to participate in the transaction.

When a client invokes finder methods on an entity definition or on an entity based view object, the framework creates entity rows for each row from the database. The state of these entity rows will be marked as Unmodified. Later when the client modifies some attributes, the state is transitioned to Modified and they become eligible to participate in the transaction.

When a client calls the remove method on an entity object, entity state becomes Deleted and it will be added to the transaction cycle.

The transaction commit cycle takes place in two phases, posting changes to the database and then committing the database transaction. On successful commit to the database, all the entities in the state New and Modified will be transitioned to Unmodified, and Deleted entity rows will be transitioned to the Dead state.


Create a row at the end of an ADF table

Okay, so the user will select a department name, and based on that, employees will be displayed. The user will click on Create button post which a blank row will be inserted where the user will have to enter valid values, and after that click on Commit to save data in database.

Okay. Some things to remember. Set the PartialSubmit property of the button to be True and the PartialTrigger of the table to be set as the ID of the button. This is the code that is executed when the user presses Create button.

import oracle.adf.model.BindingContext;
import oracle.binding.BindingContainer;
import oracle.jbo.NavigatableRowIterator;
import oracle.jbo.Row;
import oracle.jbo.uicli.binding.JUCtrlHierBinding;
import oracle.adf.model.binding.DCIteratorBinding;

    public String cb1_action() {
        // Add event code here...
        BindingContainer bc = BindingContext.getCurrent().getCurrentBindingsEntry();
        JUCtrlHierBinding hierBinding = (JUCtrlHierBinding)bc.get("EmployeesView3");
        DCIteratorBinding dciter = hierBinding.getDCIteratorBinding();
        NavigatableRowIterator nav = dciter.getNavigatableRowIterator();
        Row newRow = nav.createRow();
        newRow.setNewRowState(Row.STATUS_INITIALIZED);
        Row lastRow = nav.last();
        int lastRowIndex = nav.getRangeIndexOf(lastRow);
        nav.insertRowAtRangeIndex(lastRowIndex + 1, newRow);
        dciter.setCurrentRowWithKey(newRow.getKey().toStringFormat(true));
        return null;
    }
Now some concepts about inserting row in different places of the table:

1. User wants to create a new row as the first row of the table. In that case

newRow.setNewRowState(Row.STATUS_INITIALIZED);
nav.insertRowAtRangeIndex(0, newRow);
dciter.setCurrentRowWithKey(newRow.getKey().toStringFormat(true));
2. User wants to create a new row before the current selected row

newRow.setNewRowState(Row.STATUS_INITIALIZED);
nav.insertRow(newRow);
dciter.setCurrentRowWithKey(newRow.getKey().toStringFormat(true));
3. User wants to create a new row after the current selected row

newRow.setNewRowState(Row.STATUS_INITIALIZED);
Row currentRow = nav.getCurrentRow();
int currentRowIndex = nav.getRangeIndexOf(currentRow);
nav.insertRowAtRangeIndex(currentRowIndex+1, newRow);
dciter.setCurrentRowWithKey(newRow.getKey().toStringFormat(true));
Infact if the CreateInsert operation is dragged into the page and created as a button, the 2nd point would have been achieved.

If you set the EditingMode as 'clickToEdit', the rows will appear as read-only. Once the user clicks on a particular row, he/she can edit the row. But make sure that the row selection of the table component must be set as Single.

Difference between AutoSubmit and PartialSubmit
autoSubmit: Related to an input component (such as inputText and selectOneChoice) or a table select component (such as tableSelectOne). The component automatically submits the form it is enclosed in
partialSubmit: Releated to a command component. The page partially submits when the button or link is clicked.

If a component has its immediate attribute set to true, then the validation, conversion, and events associated with the component are processed during this phase.

setNewRowState
This method should be used to create a row and then to mark it temporary (STATUS_INITIALIZED) so that the user can use the created Row to fill UIs like Table UIs with valid default values for rows. Then when the Row values are updated, UIs should once again call this method to turn the Row into new (STATUS_NEW) state before any setAttribute calls on the Row, so that the changes are validated and posted.

Download the sample application from File Cabinet: CreateEmployee.rar

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