Wednesday, August 29, 2012

Rearranging the column of af table in oracle adf

Hi  All,

Rearranging the column of  af table in oracle adf :

Use Case:
In one of my project we have to implemented the customization feature of the adf which we also known as MDS. Where  logged in user has option to rearrange the column's  of the af table .And if user logged out and logged -in again then he/she can see the old order of columns of the table.(it will persist column order)

But our business user also want reorder the column  of the table with it's initial order.Hence we need to implement somethings which will solved their purpose .

Implementation :
Since <af:column > has attribute called  DisplayIndex which contains index value of the column which is showing in the UI .By default value is -1  it  means there is no reorder of column at client side.

If you changed the order of the column the all the columns DisplayIndex will changed with the index and index will start 0.

Again making column into initial order we need to change the value of DisplayIndex with -1.After making this it will automatically display af table with it initial af:table order .

 I have created a command button and created action listener  method and added following code

    private RichTable richTableBinding;

    public void setRichTableBinding(RichTable richTableBinding) {
        this.richTableBinding = richTableBinding;
    }

    public RichTable getRichTableBinding() {
        return richTableBinding;
    }

       public void columnActionListener(ActionEvent actionEvent) {
        List<UIComponent> uiComponentList = richTableBinding.getChildren();
        for (UIComponent uiComponent : uiComponentList) {
            if (uiComponent instanceof RichColumn &&
                uiComponent.isRendered()) {
                ((RichColumn)uiComponent).setDisplayIndex(-1);
            }
            AdfFacesContext.getCurrentInstance().addPartialTarget(richTableBinding);
        }
    }

One more things i would like to add here that is in my last post i have created declarative component which will generate the report into different type of format .

But that  declarative component has  following limitation.

As a end user if i have changed the order of the columns of the table in UI side and after that  if  i generate the report they the order of report table will same as UI .But it is not happening with current scenario .But if i implement the same post scenario in my declarative component then it  would be achievable.

 I will try to add the same in declarative component .And will post later .


Coding is present  at following link

https://docs.google.com/open?id=0B8cP4jZuxLlXUmdkcE9lWUtoX3M


Thanks ,
Prateek Shaw




Tuesday, August 28, 2012

Declarative Component in Oracle ADF (To Generate the PDF/CSV/XML/HTML type of report) Part 2

Generating PDF/HTML/CSV/XML Report in ADF :

"You can clone source code from git hub and below is address "

"https://github.com/prateekazam/ReportApp2/"

In my  last past i have explained how to generate report into PDF format.But that component is not able to generate report in HTML/CSV/XML.(Limitation )

Hence in this post i have tried to resolved all the problem which last version has. Using this you can generate report following new format .

1-XML
2-CSV
3-HTML


Declarative Component Specification(ReportDeclarative ) :

Tag-Lib Name :reportDeclarative
Tag-Lib-URL: http://www.adfwithejb.blogspot.com
Tag-Lib-Prefix :report
Component Name :ReportDeclarative

*All i have changed the Tag-Lib information .

Attribute of the ReportDeclarative  component  are following  :

S.No. Attribute Name Required Default Value Explanation
1 Button Name Yes
It will display as button name of download button
2 Report Type Yes
1-For Pdf Report :PDF
2-For Csv Report :CSV
3-For Html Report :HTML
4-For XML Report :XML
3 Report Name Yes
Name of the report.it does not require any extension
4 Table Id Yes
af:table id which you want to export into pdf 
5 Serial Number
No
False It will add one column in the table which contains serial number
6 Pagination No False Pagination in pdf.It will only applicable when report type is pdf.
7 Row Tag No
If you generating  XML report then it is required
8 Parent Tag No
If you generating  XML report then it is required
9 Serial Column Header No S.No. If you are generating report with serial number then by default column header will be S.No. If you want to change then you can replace it  here.


Following Feature added in this version which were not presented  in last version .

1-Exception handling is implemented
2-Pagination is implemented
3-Serial Number
4-XML Report Support
5-HTML Report Support
6-CSV Support
7-Region Support
   You can use this component in Region as well .

Since only pdf report  require itext  API so do not forget to add itext jar file in project  which is present at following link.

http://www.4shared.com/file/a8rSo6rk/itextpdf-510.html

Download component jar at following line :

https://docs.google.com/file/d/0B8cP4jZuxLlXbWs2TjNwZzFvdGM/edit
(This time i have been uploaded file in google document  )

* I have already mentioned in  my last how to add declarative component jar in the project. 

I tested this with multiple scenario and it is working for me.Please let me know if you will get any type of exception or error.

PDF Report:
 *You can generate pagination
 *You can add serial number and you can change serial column header by default will S.No.
 

CSV Report :
  *CSV file contains comma separate value.
  *So if you are using Open office then you have to check separate by comm .
  *Pagination is not applicable
  *You can add serial number and also you can change the default serial column header value.
  *It is same as note file hence Header will not come as bold . 

HTML Report :
*You can add serial number and also you can change the default serial column header value.
*Pagination is not applicable 


XML Report :
*Column name will come as opening tag and closing tag.
*You need to provide parent tag of the column in Raw Tag attribute of the declarative component
*All the parent tag should also have parent therefore you also need to provide parent tag value in Parent Tag attribute of the declarative component.
*No pagination will work .

Any comment will appreciated .

Thanks
Prateek

Wednesday, August 15, 2012

Declarative Component in Oracle ADF (To Generate the PDF/CSV/XML type of report)


Declarative Component in Oracle ADF (To Generate the PDF/CSV/XML type of report) :

Since adf faces does not have any component which help us to download the report (s) in to following format .

1)PDF
2)HTML
3)XML
4)CSV
or might be other different format .(In  case if you know any other format please let me know )

In one of my application where we need to generate the reports in to pdf format therefore  we thought  to create the declarative components which will support us to generate the reports into pdf format and in this post i am going to explain the same .

Here i am not going to share how to create the declarative component. Although i would like to share the following link which is might be use full .

1-http://docs.oracle.com/cd/E18941_01/tutorials/jdtut_11r2_40/jdtut_11r2_40.html
2-http://docs.oracle.com/cd/E17904_01/web.1111/b31973/af_reuse.htm#CHDDECDG

Above two link  will be give some grip on the jsf /adf  declarative  component  creation .

Please download following two jar to use the component which i has been created
First jar contains source of the component and second jar is itext pdf generation jar (which is open source)

First :
You can download the jar file using following link (declarative component jar location)

Second :
For download itext  jar :
http://www.4shared.com/file/a8rSo6rk/itextpdf-510.html

Step to add the jar in project after that you can able to use in your project . 

1- download and put into local location .
2-Go to the Resource Palette  

3-Here we need to create the file system to access the jar file into the project.
4-Please follow the following pictorial step to create the file  system connection 











* exclude jar file name .For example if folder A contains jar then path should be A:\ 

Select the file system option and fill the above details .
5-Add the jar into the project .

Your jdeveloper is  ready to consume the declarative component .

Go to the component palette and in the drop down select the complib (i know here tag lib  name is not meaning full but in the next release(version) i will change the name with the appropriate name  )
image is following 



Till here it is common practice to consuming the declarative  component .see the following link if still you  have any confusion to how to use the declarative components


Declarative Component Specification(ReportDeclarative ) : 

Tag-Lib Name :compLib
Tag-Lib-URL: /componentLib
Tag-Lib-Prefix :report
Component Name :ReportDeclarative 

Attribute of the ReportDeclarative  component  are following  :

S.No. Attribute Name Required Explanation
1 Button Name Yes It will display as button name of download button
2 Report Name Yes Name of the report.it does not require any extension 
3 Report Type Yes This version will support only pdf .So put PDF .if you  will give
other than this it will not work and also it not going to give any
error message (this feature will come in next version or release )
4 Table Id Yes af:table id which you want to export into pdf 


This version will support only the PDF report but in  the next version i will try to support the CSV and XML type of report.

Consideration point( Limitation ) :

1-Each column width will same .
2-Pdf width percentage is set to 100 %
3-Table Columns header will come as the pdf table columns.
4-Render false column will not going to shown on the pdf report
   same as af:exportCollectionActionListener components behavior
5-It is internally using the itextpdf-5.1.0.jar.it means here  i am using itext 5.1 version to generate the pdf .
6-Before going to use the component please download the same version of jar file of the itext and add into the project.
7-No exception handler implemented yet .It means if you are providing wrong table id or wrong report type it not going to give any type of message into the UI regardless you will able to download the file which will  corrupt.
8-Column width same regardless if one column contains less length of value to other column.
9-Need to test if you are using table inside  region or any other parent container.Because at run time client id changed based on parent id.
i.e.I tested  it using af:table with direct child with the af:form
sample code is following :--

<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:af="http://xmlns.oracle.com/adf/faces/rich"
          xmlns:report="/componentLib">
  <jsp:directive.page contentType="text/html;charset=UTF-8"/>
  <f:view>
    <af:document id="d1">
      <af:messages id="m1"/>
      <report:reportDeclarative buttonName="Employee" reportType="PDF"
                                tableId="t1" id="rd1" reportName="sample"/>
      <af:form id="f1">
        <af:table value="#{bindings.ViewObj1.collectionModel}" var="row"
                  rows="#{bindings.ViewObj1.rangeSize}"
                  emptyText="#{bindings.ViewObj1.viewable ? 'No data to display.' : 'Access Denied.'}"
                  fetchSize="#{bindings.ViewObj1.rangeSize}"
                  rowBandingInterval="0"
                  selectedRowKeys="#{bindings.ViewObj1.collectionModel.selectedRow}"
                  selectionListener="#{bindings.ViewObj1.collectionModel.makeCurrent}"
                  rowSelection="single" id="t1">
          <af:column sortProperty="EmployeeId" sortable="false"
                     headerText="#{bindings.ViewObj1.hints.EmployeeId.label}"
                     id="c7" width="210">
            <af:outputText value="#{row.EmployeeId}" id="ot6">
              <af:convertNumber groupingUsed="false"
                                pattern="#{bindings.ViewObj1.hints.EmployeeId.format}"/>
            </af:outputText>
          </af:column>
          <af:column sortProperty="FirstName" sortable="false"
                     headerText="#{bindings.ViewObj1.hints.FirstName.label}"
                     id="c4" width="0">
            <af:outputText value="#{row.FirstName}" id="ot4"/>
          </af:column>
          <af:column sortProperty="LastName" sortable="false"
                     headerText="#{bindings.ViewObj1.hints.LastName.label}"
                     id="c2" width="105">
            <af:outputText value="#{row.LastName}" id="ot5"/>
          </af:column>
          <af:column sortProperty="Email" sortable="false"
                     headerText="#{bindings.ViewObj1.hints.Email.label}" id="c5"
                     width="105">
            <af:outputText value="#{row.Email}" id="ot9"/>
          </af:column>
          <af:column sortProperty="PhoneNumber" sortable="false"
                     headerText="#{bindings.ViewObj1.hints.PhoneNumber.label}"
                     id="c10" width="105">
            <af:outputText value="#{row.PhoneNumber}" id="ot7"/>
          </af:column>
          <af:column sortProperty="HireDate" sortable="false"
                     headerText="#{bindings.ViewObj1.hints.HireDate.label}"
                     id="c3" width="105">
            <af:outputText value="#{row.HireDate}" id="ot11">
              <af:convertDateTime pattern="#{bindings.ViewObj1.hints.HireDate.format}"/>
            </af:outputText>
          </af:column>
          <af:column sortProperty="JobId" sortable="false"
                     headerText="#{bindings.ViewObj1.hints.JobId.label}" id="c9"
                     width="105">
            <af:outputText value="#{row.JobId}" id="ot3"/>
          </af:column>
          <af:column sortProperty="Salary" sortable="false"
                     headerText="#{bindings.ViewObj1.hints.Salary.label}"
                     id="c1" width="105">
            <af:outputText value="#{row.Salary}" id="ot10">
              <af:convertNumber groupingUsed="false"
                                pattern="#{bindings.ViewObj1.hints.Salary.format}"/>
            </af:outputText>
          </af:column>
          <af:column sortProperty="CommissionPct" sortable="false"
                     headerText="#{bindings.ViewObj1.hints.CommissionPct.label}"
                     id="c11" width="105">
            <af:outputText value="#{row.CommissionPct}" id="ot8">
              <af:convertNumber groupingUsed="false"
                                pattern="#{bindings.ViewObj1.hints.CommissionPct.format}"/>
            </af:outputText>
          </af:column>
          <af:column sortProperty="ManagerId" sortable="false"
                     headerText="#{bindings.ViewObj1.hints.ManagerId.label}"
                     id="c8" width="105">
            <af:outputText value="#{row.ManagerId}" id="ot1">
              <af:convertNumber groupingUsed="false"
                                pattern="#{bindings.ViewObj1.hints.ManagerId.format}"/>
            </af:outputText>
          </af:column>
          <af:column sortProperty="DepartmentId" sortable="false"
                     headerText="#{bindings.ViewObj1.hints.DepartmentId.label}"
                     id="c6" width="105">
            <af:outputText value="#{row.DepartmentId}" id="ot2">
              <af:convertNumber groupingUsed="false"
                                pattern="#{bindings.ViewObj1.hints.DepartmentId.format}"/>
            </af:outputText>
          </af:column>
        </af:table>
      </af:form>
    </af:document>
  </f:view>
</jsp:root>


10-try to achieve same as  af:exportCollectionActionListener
11-Serial number need to add into the report.

New Feature(which will come into later release) :

1-XML report support.
2-CSV report support.
3-Exception handling (first we check whether report got successfully created or not.If not we will show the message into the pop up).
4-Source code
5-column width (column with come as same whatever is there in UI)
6-Need to change the tag lib name
7-Generate the report regardless the table structure .(no need to bother about where table will present )


At last i know here i did not explain internal functionality of the class which i have created but in next release sure i will share the source code as well.


Any suggestion would be appreciated.Any enhancement or any other feature which you want please share with me.
 
Please see this link for new declarative component 
http://adfwithejb.blogspot.in/2012/08/declarative-component-in-oracle-adf-to_28.html

Thanks
Prateek

Friday, August 10, 2012

Implementing Select One ,Select None and getting Selected row in Backing Bean of af:table

Hi,

I came across one common  use case where we need to have select all ,select none and also we need to get selected rows into backing bean which later we want to perform operation on select records of af table.
Following use case are also part of the same use case.

1->User want to delete selected rows at a time.
2->User want to update selected rows at a time.i.e. approve or reject.
3->Delete all the rows at once.

Even though you can find allot of solution of this problem on internet but they contains allot of java code.But in my solution i try to minimizing the  java code   .

I have divided my way of implemention  approach following part.

1-Since we require check box for selecting the rows .So for creating the check box at model layer is first part.
2-Getting the selected row into the backing bean is second part.
3-Selecting or deselecting all rows at once in af:table is third part .


1-Creating the check box in af:table :

We can use ADF BC as model layer or EJB 3.0 .Here i have been used the EJB 3.0 hence i am going to first explain though EJB 3.0.

Steps are following :


1-Create the  enitiy bean from table using Employee table.
2-Then i have added one attribute name as checkBox  as Boolean type .
    code are  following
    @Transient
    private Boolean checkBox;
3-Make this attribute as  @Transient and create the setter and  getter of the checkBox.
4- Create the Session bean and then data control.
5-Go to the Employee.xml file which has been created after data control .Select checkBox attribute and click the edit button and select controls hints and change the control type value default to check box.(By doing this when we drag and drop the table in jspx page the checkbox automatically come as check box).
6-Drag and drap the employeeFindAll method which has been created automatically when you create the data control .Moreover this method will return the all employee value list from the data.Since i need to show the af:table on ui so i am going to drag and drop this method as af:table (do not select af:table read only because check box should be editable.later you can make other columns read only on basis of requirment)

"If you are using ADF BC as model layer then  you just need  to do the same thing in the VO,it mean  add one transient attribute and later change it to check box same thinks which i did in EJB"

The first step has been finished.Our jspx page is ready with one af:table where we have first column as select check .


2-Getting the selected row into the backing bean:

I have created the value change listener of select one choice where  i am check whether the select box is selected or not .


    public void valueChangeListener(ValueChangeEvent valueChangeEvent) {
        Boolean value = (Boolean)valueChangeEvent.getNewValue();
        Row exmapleObject =
            (Row)evaluateEL("#{bindings.employeeFindAll.currentRow}");
        AdfFacesContext context = AdfFacesContext.getCurrentInstance();
        Set list = null;
        if (value) {
            Object object = context.getPageFlowScope().get("selectedRows");
            if (object == null) {
                list = new HashSet();
                context.getPageFlowScope().put("selectedRows", list);
            }
            Set adding = (Set)context.getPageFlowScope().get("selectedRows");
            adding.add(exmapleObject.getAttribute("employeeId"));
            context.getPageFlowScope().put("selectedRows", adding);
        } else {
            Set removing = (Set)context.getPageFlowScope().get("selectedRows");
            removing.remove(exmapleObject.getAttribute("employeeId"));
        }
    }

3-Selecting or deselecting rows at once in af:table:

selectAllRowButton is responsible for making all the rows selected and deSelectAllRowButton is for deselection the row,



    public void selectAllRowButton(ActionEvent actionEvent) {
        AdfFacesContext context = AdfFacesContext.getCurrentInstance();
        Set list = null;
        Object object = context.getPageFlowScope().get("selectedRows");
        if (object == null) {
            list = new HashSet();
            context.getPageFlowScope().put("selectedRows", list);
        }
        Set adding = (Set)context.getPageFlowScope().get("selectedRows");
        RowSetIterator rowSet = getTableIterator();
        while (rowSet.hasNext()) {
            Row row = rowSet.next();
            row.setAttribute("checkBox", Boolean.TRUE);
            adding.add(row.getAttribute("employeeId"));
        }
        rowSet.closeRowSetIterator();
        context.getPageFlowScope().put("selectedRows", adding);
        AdfFacesContext.getCurrentInstance().addPartialTarget(tableBinding);
    }

    public void deSelectAllRoButton(ActionEvent actionEvent) {
        AdfFacesContext context = AdfFacesContext.getCurrentInstance();
        Set list = null;
        Object object = context.getPageFlowScope().get("selectedRows");
        if (object == null) {
            list = new HashSet();
            context.getPageFlowScope().put("selectedRows", list);
        }
        Set removing = (Set)context.getPageFlowScope().get("selectedRows");
        RowSetIterator rowSet = getTableIterator();
        while (rowSet.hasNext()) {
            Row row = rowSet.next();
            row.setAttribute("checkBox", Boolean.FALSE);
            removing.remove(row.getAttribute("employeeId"));
        }
        rowSet.closeRowSetIterator();
        context.getPageFlowScope().put("selectedRows", removing);
        AdfFacesContext.getCurrentInstance().addPartialTarget(tableBinding);
    }


* One point which i would like to share here that is  in all three method i am setting the selected employee id value into page flow scope.

Here i am first checking  a variable that  is the variable is present in page flow scope or not.if it is null i page flow first i created the new instance of the Set and adding into the page flow scope .If the user clicked on the any check box of the table first i am getting the selected row and adding  the value in the set which is present in page flow and after adding value into set i am again putting the value in page flow scope.

And if the user deselected the check box then i am again the getting the value from page flow and removing from the set and again adding into the page flow .

Although i explained model layered as EJB 3.0 but from the data controls till  UI the approach would be same  in ADF BC.


Project source code is available on following url

http://www.4shared.com/rar/etlDbINh/SelectAllAndNone.html


Thanks
Prateek

Thursday, August 2, 2012

Calling af:fileDownloadActionListener component programmatically

I had one use case where i need to called af:fileDownloadActionListener programmatically .Let me exaplain the use case first.

Use case: Business user or any user want to download the zip file which contains text's file .But the zip file if going to generated at run time on the basis of the some tough business rule's.It's mean if there is any  failure in business rule then in this case zip file is not going to generated and same time we i need to show the appropriate message to the user.

*If you use af:fileDownloadActionListener directly then if there is no file for download to user so it will  be give error message to user.(this is default feature of the af:fileDownloadActionListener )

So ,if there is some business false in that case i need to skip the file down load listener (to avid to show the error message for example unable to load file  some things like this ).

For over come this use case or problem i have used two command button.let me explain why i used two button and what are they used for ?

1-first button should be visible and it will just call the backing bean method where i have written the business logic for generating the zip file.
(For user prospective he/she thinks this button is  for download but instead-of download task the button is going to call the backing bean.)

2-Second button will going to do actual task and button  have actuall file download listener however it's not going to show on UI.

let me expalin in more details

First command is following which clicking  on the i am calling the a backing bean method


     <af:commandButton text="#{bsnlbillpaymentuiBundle.DOWNLOAD}" id="cb3" disabled="#{!bindings.ExecuteWithParams.enabled}"
                          actionListener="#{backingBeanScope.paymentDataBsnl.validationRecords}"
                          clientComponent="true">
                          </af:commandButton>

In the validationRecords backing bean method i am checking whether do we need to create the zip file or not.And in this method i am checking is the zip file got created or not if not then show the custom pop up with message and if the zip file is present then i am calling the java script where i am queuing the event of the second command button which has the af:filedownloadlistener.

Backing bean method has following code .


        public void validationRecords(ActionEvent actionEvent) {
        ADFContext ctxt = ADFContext.getCurrent();
        SecurityContext sctxt = ctxt.getSecurityContext();
        if (business rule) {
                 FacesContext context = FacesContext.getCurrentInstance();
                ExtendedRenderKitService erks =
                    Service.getService(context.getRenderKit(),
                                       ExtendedRenderKitService.class);
                FacesContext.getCurrentInstance();
                String id =
                    button.getClientId(FacesContext.getCurrentInstance());
                erks.addScript(context, "customHandler('" + id + "');");
            } else {
                String msg = "No Records is found ";
                FacesMessage fmsg =
                    new FacesMessage(FacesMessage.FACES_MESSAGES, msg);
                FacesContext context = FacesContext.getCurrentInstance();
                context.addMessage(null, fmsg);
            }
      }


Here in this line  erks.addScript(context, "customHandler('" + id + "');"); 

We are calling java script method which has following code 


 var customHandler= function(event) { var component = AdfPage.PAGE.findComponent(event); var actionEvent = new AdfActionEvent(component); actionEvent.queue(); }

In  java script method i am passing the client id of the second button which i have  already bind to backing bean.Moreover in this method i am also queuing  the event to second button.

And second method has following code which actually has af:fileDownloadlistener component.

     <af:commandButton text="NONE" id="cb1" action=" "
                        disabled="#{!bindings.ExecuteWithParams.enabled}" visible="false"
                        clientComponent="true"
                        binding="#{backingBeanScope.backingBean.button}">
          <af:fileDownloadActionListener
                                         method="#{backingBeanScope.backingBean.fileDownload}"/>
               </af:commandButton>

* This is one way to achieve this type of problem or use case.People might have another way to do.Any suggestion will appreciated.

Thanks
Prateek Shaw