Thursday, October 11, 2012

Insert Rows in to ADF View Object Programatically

Following are the use cases pertaining to this topic

1. Insert Rows into ADF View Object Programatically.
2. Insert Rows into a ADF View Object from a ADF Table which is a combination of multiple tables (for example : ADF Table in the jsp page contains mixture of columns from various tables and we need to take only some column data and save it in target ADF VO.

Create a View object from multiple entities (( Assuming you have a View Object SourceVO1 ).Drag and drop the View Object data control on to the page as ADF Table.Create an ADF button at the bottom of the table. Create Action Listener for the button. you must have the target View Object ready to store the values. Since you have created ADF Table on the page the binding section will have the bindings created for the View Object and to access its collection model .For more on bindings section ADF Bindings. Now we need to add the target View Object to the page bindings section.

This part of the section also describes about How to Create Tree Table binding.
Go to the Bindings section of your page. Click Plus icon

 Select tree from the Insert Item window and click ok.


Click Add button as shown . This will list all of the View Objects added to the Application Module

 Choose the desire View Object in which you are going to save the records.


























Click at the plus icon and select Add Rule .

























This window will bring down all of the attributes that target view object has.you can shuttle the necessary attributes to the righter side and click ok . Now the Target View Object added as Tree binding can be seen under Bindings section.




























Now we will write the java code to insert rows. As we have already created an Action Listener for the button,go to the method of that java class and write this code.

//Code to get the bindings for TargetVO :
    
         DCBindingContainer bindings2 =
            (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
             
        JUCtrlHierBinding obj = (JUCtrlHierBinding)bindings2.findCtrlBinding("ProgrammaticVO1");
        ViewObject targetVO = obj.getViewObject();


   DCBindingContainer bindings =
            (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
        DCIteratorBinding empIter =
            bindings.findIteratorBinding("SourceVO1Iterator");

//SourceVO1Iterator is the iterator under Executables section for the SourceVO1 bindings.

        RowSetIterator roleRSIters = empIter.getRowSetIterator();
        RowSetIterator rs1 = roleRSIters.getRowSet().getViewObject().createRowSetIterator(null);
        NameValuePairs nvp = null;

        while (rs1.hasNext()) {
            Key key = rs1.next().getKey();
            Row r = rs1.getRow(key);           
           
            nvp = new NameValuePairs();
            nvp.setAttribute("Empid",r.getAttribute("EmployeeId"));
            nvp.setAttribute("Nameone",r.getAttribute("FirstName"));
            nvp.setAttribute("Nametwo",r.getAttribute("LastName"));
            targetVO.createAndInitRow(nvp);
         }
       
        rs1.closeRowSetIterator();
        targetVO.getApplicationModule().getTransaction().commit();

Getting the View object in MB and performing operations on it is not a good practice.

Tuesday, October 9, 2012

How to Identify a View Object is modified

There are cases where we need to show the modified VO rows in separate pop up window or highlight the modified/new rows .

I have a quiet interesting usecase in my development project and thought i would write about it . The usecase is tat an ADF Table in the ui page can  be modified and new rows can also be created.After modifying some of the rows the user has navigated to some other page without committing the modified data. At this point i need to stop the user and alert him saying that some of the VO rows have been modified.

This is a direct approach and can be done in two ways. Either in the managed bean or in the design time page using expressions.According to ADF new/modified rows will be in cache.

Download the Sample Application and run CatchModifiedRows.jspx page.

we will continues using the workspace which i have been using for the earlier post .
Lets start developing it. Create a jspx page CatchModifiedRows.jspx . Drag and drop EmployeesVO1 on to the page as ADF Table and keep the necessary columns you want.keep a button at the bottom of the ADF table to navigate to some other page.












Create Action Listener for the Next button and name the bean as ModifiedVOBean.java and method as chkmeth. Inside the method get the bindings for the EmployessVO1 .

        DCBindingContainer bindings2 =
            (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
              
        JUCtrlHierBinding obj = (JUCtrlHierBinding)bindings2.findCtrlBinding("EmployeesVO1");
        ViewObject targetVO = obj.getViewObject();


we can get the current status of the view object instance using a method isDirty().

Boolean b = targetVO.getApplicationModule().getTransaction().isDirty();

This gives Boolean value of True/False . If something is modified/created the value will be True else False.



Final piece of code is

    public void chkMeth(ActionEvent actionEvent) {
       
        DCBindingContainer bindings2 =
            (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
              
        JUCtrlHierBinding obj = (JUCtrlHierBinding)bindings2.findCtrlBinding("EmployeesVO1");
        ViewObject targetVO = obj.getViewObject();
        Boolean b = targetVO.getApplicationModule().getTransaction().isDirty();
       FacesMessage msg=null;
        Boolean ev = false;
        if(b!=ev){
        msg=new FacesMessage("Hold on ,you have unsaved data.pls commit before proceeding");
        FacesContext.getCurrentInstance().addMessage(null,msg);
        }

  }


The boolean result  can be evulated against True/False and based on it we can throw a message to the user . Now go to the page and change something in any of the column and click Next. you will get the message.Further  you can customize the implementation the way u want like information in the pop up dialog
and so on.



we can also able to get Entity level status from VO using this code

RowSetIterator rs1 =targetVO.createRowSetIterator(null);
while (rs1.hasNext()) {
  EmployeesVORowImpl r = rs1.next();
  Entity eo = r.getEntity(0);
byte currentState= eo.getEntityState();
if(currentState==EntityImpl.STATUS_NEW .......)
{
 ......
}
}

From design time we can access the row status using the following expression
Expression #{row.row.entities[0].entityState}

Getting the View object in MB and performing operations on it is not a good practice.

Thursday, June 21, 2012

ADF Dynamic Region | Working with Oracle ADF Dynamic Regions

ADF Region is used to render a bounded taskflow in a JSF page . The primary use of ADF Region is u can put  various pieces of application functionality in a bounded task flow. A single JSF page can contain many taskflows added as regions and each region may contain different content.


The sections pointed with arrows are different taskflows added as as a regions in a single JSF Page.The Taskflow which is added as ADF Region must contain at least one view activity.

Difference between ADF Region and Dynamic Region ?

Region added in a JSF Page can be invoked based on some action like button click or link that renders specific taskflow in which the region formed . various regions can also be displayed as a stand by at a time when the page loads.In Dynamic Region you do not need to drag and drop the required regions on to the JSF page instead your taskflows will be identified by using the taskflow ID on some action. The task flow binding dynamically determines the values of its ID at run time . In the above picture i have dragged and dropped four taskflows as a region in a JSF Page . But Dynamic Region simplifies this and allows us to swap between taskflows using Dynamic Region link where it store the task flow id in a managed bean and render the pages based on the task flow ID it gets at runtime .

Hope this gives you the basic idea on the concept and we will move ahead for creating one .

Download sample application with this post 

we are not going to alter our Model project as we will use the existing VOs which we created in earlier posts .Those who want to continue with the workspace that contains all model components can download from here AdfDemoApps.

Create two taskflows :
AdfDemoApps\AdfDemoUi\public_html\WEB-INF\TaskFlows\CountriesFlow.xml,
AdfDemoApps\AdfDemoUi\public_html\WEB-INF\TaskFlows\EmployeesFlow.xml

Create two page fragments :
AdfDemoApps\AdfDemoUi\public_html\pages\CountriesRegionPage.jsff
AdfDemoApps\AdfDemoUi\public_html\pages\EmpRegionPage.jsff


Drag & drop the CountriesRegionPage.jsff in CountriesFlow.xml and  EmpRegionPage.jsff in EmployeesFlow.xml.We need a jsp page to run these taskflows. Create a JSF Page DynamicRegionMain.jspx under AdfDemoApps\AdfDemoUi\public_html\pages. In the Create JSF Page dialog under Initial Page Layout and Content section i have selected Oracle Three Column Layout for the rich look and to split the user screen into two so that we can have action links at one side and actual pages at other side.

Now Drag and drop the EmployeesFlow.xml into the DyamicRegionMain.jspx we just created and select Dynamic Region. In the Next step it will ask you to specify Managed Bean . Click Add symbol  and create one .  Bean name is DynamicRegionBean under package bean and click ok. you can also create managed bean separately and  choose from the drop down. click ok in the Edit Task Flow Binding dialog.





The next two steps are important

Drag and drop the EmployeesFlow.xml  in the left panel of the page and choose Dynamic Region Link > dynamicRegion1.
Drag and drop the CountriesFlow.xml  in the left panel of the page and choose Dynamic Region Link > dynamicRegion1.
As we already have one Dynamic Region we are appending our taskflows to the same region link .

When you drop a taskflow onto a JSF page to create an ADF dynamic region , JDeveloper adds an af:region tag to the page . This tag contains a reference to a task flow binding


<f:facet name="center">
            <af:region value="#{bindings.dynamicRegion1.regionModel}" id="r1"
                       partialTriggers="::cl1 ::cl2"/>
 </f:facet>



An ADF dynamic region link swaps the taskflows within an ADF dynamic region . Look at the below code snippet in the DynamicRegionBean. java
 
Jspx :

     <af:commandLink text="EmployeesFlow"
                              action="#{viewScope.DynamicRegionBean.employeesFlow}"
                              id="cl1"/>
              <af:spacer width="10" height="10" id="s1"/>
      <af:commandLink text="CountriesFlow"
                              action="#{viewScope.DynamicRegionBean.countriesFlow}"
                              id="cl2"/>
Bean :

    private String taskFlowId =
        "/WEB-INF/TaskFlows/EmployeesFlow.xml#EmployeesFlow";

    public DynamicRegionBean() {

        super();

    }

    public TaskFlowId getDynamicTaskFlowId() {

        return TaskFlowId.parse(taskFlowId);
    }

    public String employeesFlow() {

        taskFlowId = "/WEB-INF/TaskFlows/EmployeesFlow.xml#EmployeesFlow";
        return null;
    }

    public String countriesFlow() {

        taskFlowId = "/WEB-INF/TaskFlows/CountriesFlow.xml#CountriesFlow";
        return null;
    }

The Managed bean stores the value of the task flow ID that displays inside the dynamic region
when a user click on any link its corresponding method will be called and thus taskFlowId will be changed and corresponding page will be rendered.

Note :
you can add an ADF Dynamic Region Link if you already have at least one ADF Dynamic Region on a page. a menu displays all of the dynamic regions currently on the page

Save All .  Right Click on DynamicRegionMain.jspx and choose Run . The Output

 

Wednesday, June 20, 2012

Creating a Master-Detail Relationship Using Oracle ADF

Master Detail Relationships using Oracle ADF allows you to view data from related tables at same time. we often face a situation in Software Development where we need to display some rows based on a row data from some other table . To put it more simple ,  in a page you have the first table that holds countries information and a table below to it contains the locations information . when you click on a row in countries table then automatically all the locations pertaining to the country should display. There are various ways in various J2EE frameworks provides this functionality. what is so special about ADF in giving this functionality.Yes, it is . ADF Model along with View Controller does many things for you .  Lets see how this works

Pre-requisites:

HR Schema in Oracle database with tables

For those who are new to ADF can go through this link Oracle ADF Model Sample Application download and can find a sample application to start with this post or else can simply download the complete application Oracle ADF Master-Detail Relationship Sample Application.

ADF Model project holds all the View Objects and View Links, and ADF View Controller project holds all the UI Pages like jsff, jspx etc ..

Right Click on mode.entity package under AdfDemoModel and create two entity objects

CountriesEO
LocationsEO

Right Click on mode.viewpackage under AdfDemoModel and create two view objects

CountriesVO
LocationsVO

Note : (when you create EO and VO for Locations table, Association LocCIdFkAssoc, ViewLink LocCIdFkLink will be created by ADF for you)  But why a View link is needed ? Look at the picture





ViewLink is a join condition between two view objects. Read ADF View Link. Now go back to your ADF Application Module AppModule and see the Data Models section

 
 LocationsVO via LocCIdFkLink has come under CountriesVO automatically . This means LOCATIONS table in the Database already has a foreign key reference to the COUNTRIES table and when we try to create a LocationsVO , ADF understood the relation and created a View Link for us . So based on this relationship, Locations Information can be retrieved based on the country id with the use of View Link . we will see this later how did this happen in UI part.

Open model.applicationmodule >> AppModule >> Data Model

Shuttle CountriesVO to the right side.
Being CountiesVO1 selected at right side, shuttle LocationsVO via LocCIdFkLink to the right side
Now shuttle the CountriesVO to the right side in the AM .



 Save All.
 You can test it using  Business component Browser which is useful to check the business logic and relation in your Application without creating any User Interface,Right  click on AppModule and choose Run 

 ..












                             All to set start with building UI Components ..what we need to have in the UI Project.
Right Click on Web Content > > AdfDemoUi From New Gallery , select JSF from categories section which is in the left side and select ADF Task Flow in the right side and click OK


MasteDetailFlow.xml being opened in the editor, drag and drop  View component from Components Palette on to the MasteDetailFlow.xml diagram . Change the name from view1 to MasterDetailView. Double click on view and enter the filename and path as such in the screen shot













Drag Panel Stretch Layout from Layout under Component Palette on to the jsff page we just created. Now Drag LocationsVO1 under CountriesVO1 and drop on to the jsff page and select ADF Master Table ,  Detail Table.
Save All..









     In Order to run this , we need to have jspx page . we cannot able to run jsff pages bcoz it is not a runnable target for ADF Controller. so I created a jspx page called MasteDetailMain.jspx under pages package,drag & drop the MasterDetailFlow.xml on to the jspx page as a Region . Save All . Now Right Click on the page and Run











Click on any country in the countries table to get its  locations only in the locations table.Later you can customize your page to look rich like labeling with proper header names, surrounding with table borders and many more . 

Logical Questions : 

How did the Detail table rendered based on the Master Data or How Master-Detail Table Relationships works in ADF ?

The  Parent tag of the detail component automatically has the partialtriggers attribute set to the id of the master component . At Runtime the partial trigger attribute  causes only the detail component tobe rendered when the user makes a selection  in the master component . In our MasterDetailView.jsff source

<af:table partialTriggers="::md1"
                    rows="#{bindings.LocationsVO1.rangeSize}"
                    fetchSize="#{bindings.LocationsVO1.rangeSize}"
                    emptyText="#{bindings.LocationsVO1.viewable ? 'No data to display.' : 'Access Denied.'}"
                    var="row" value="#{bindings.LocationsVO1.collectionModel}"
                    rowBandingInterval="0"
                    selectedRowKeys="#{bindings.LocationsVO1.collectionModel.selectedRow}"
                    selectionListener="#{bindings.LocationsVO1.collectionModel.makeCurrent}"
                    rowSelection="single"
                    binding="#{backingBeanScope.backing_pages_MasterDetailView.t1}"
                    id="t1" inlineStyle="width:500.0px;">




where md1 is the ID of parent table , so whenever user makes a selection in the master table will also cause the detail table to change which is called partial rendering 

what if i want to have ADF Master - Detail on separate pages ?

Create two jsff pages . One page contains master table and another contains child table . Create a button in the master table which navigates to the child page on the button click and Vice Versa. You may wonder how do we get the Child records based on a row selected in the master table which is in diff page. Yes ADF does automatically based on the partial triggers set . You do not need to set any variable or attribute in some scope to retrieve information.