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();
        }
    }