Sunday 20 November 2016

Drill Down Graph

It has been long time since our last post. Fortunately we have been quite busy. For this post, we have decided to show you how to implement a “drillable” graph.
Although documentation is out there, we couldn’t find a proper tutorial for this task, which mean that it could possible save you some time doing the proper research.
Key Fact: At difference of what you might have originally thought, the drillable functionality doesn’t depend on Master-Detail relationships between view objects (when your model is using ADF BC). Instead, it will look into one viewObject and from there, the functionality is implemented by the graph component according to the bindings definition configuration.
Key Fact #2: Don’t try to implement this solution using, for example, a PieChart graph. It won’t work. We are not sure why it won’t work so hopefully someone that reads this article will help us and point us to the answer.
We will explain you step by step so you can actually understand what is going on rather than just copying and pasting some random code into your application. Example will be based on Departments and Employees from HR Schema.
We are using JDeveloper 12.c but this should work in previous version as well. Please let know if it does not. So lets start by dragging and dropping the EmployeesVO from the DataControl into our page and selecting as the Bars type.
Selection_043
Now we logically want the bars to represent the salary and the department to be shown in the X axis:
Selection_044
If we run the application now, this is what we are going to get. It is basically all salaries for employees in all the departments:
Selection_045
Having a look to the page definition we see the following:
Selection_046
Now, we want to group by departments (agregateDuplicates) and we want the salary to be SUMMED (defaultAgregateType)
Selection_047
After we apply the changes and we re run the application, we can see now that salaries are summed and grouped by departments
Selection_048
Now, we want to drill down by department. So for this, we need to go again to the graph’s page definition and specify how the hierarchy is supposed to work. We need to specify what is the drillable item (item) and what are we going to show after the drill is done (child). Also, we need to tell that the graph will be replace when drilling.
Selection_064
And last thing to do is to indicate that the graph is drillingEnabled.
Selection_065
After all is done, this is what we get by running the application:
Selection_049
If we select department 80 we drill down:
Selection_050
Great! Now, what can we do to improve the presentation and the user experience? Two things:
1.- Show a multicolored graph rather than just one colour for the bars. Simple, just go to the page definition file (not the source code) and edit the graph, click Swap Bars With  and save your change.
Selection_051
After running the application you will see:
Selection_052
Drilling down:
Selection_053
2.- As you can imagine, displaying the DeparmentId  is not a real use case. So in order to show the department name you could do the following. You need to create a ViewCriteria for DepartmentVO based on DepartmentId.
Selection_057
Now, you need to add a view accessor to DepartmentsVO in the EmployeesVO. You can rename it EmpDepartment for example.
Selection_058
Edit it and apply the ViewCriteria and add the binding variable value to be DepartmentId.
Selection_059
Add the transient attribute DepartmentName and base it on a groovy expression as follows:
Selection_061
In the view controller project, go to the source code of the graph’s page definition and replace DepartmentId with DepartmentName.
Selection_056
This should be enough. Run your application and you are done:
Selection_062
Selection_063
We are currently working into an alternative way to ‘drillDown’ graphs. This approach won’t be using standard graph functionality but taskflow navigation instead.

Thursday 17 November 2016

How to hide adf tree leaf node icons

If you are working with Oracle ADF, you must have a menu with af:tree component here or there. i also used af:tree as main menu, but there was this annoying expand icon for leaf nodes. i googled it for a while and searched in forums, nothing has appeared. so i solved this with kind of tricky solution.
this is how a recursive af:tree looks like with expand icons on leaf nodes:
as you see, we can’t figure out which one is leaf node that has no child. you should try to expand to see if there are child nodes:
and here is tricky part. we need a 10px * 10px white spacer image and some inline styling in af:tree nodeStamp facet. initial facet code is:
<f:facet name="nodeStamp">
  <af:outputText value="#{node}" id="ot1"/>
</f:facet>
then i added af:image and css positioning. but most important part is rendered attribute.
<f:facet name="nodeStamp">
  <af:group id="g1">
    <af:image id="i1" source="/i/spacer.png" rendered="#{node.children == null}"
              inlineStyle="position: absolute; margin-left:-17px;
                           border: 2px solid white; width: 15px; height: 10px;"/>
    <af:outputText value="#{node}" id="ot1"/>
  </af:group>
</f:facet>
i added red border styling to make easy to see where spacer image is located and how it covers expand icon.
this tricky solution has challenges like adf skinning. i am using blafplus-rich skin family and white spacer is suitable for me. if you have another skin, you may need different image or css styling.

Monday 22 August 2016

Using f:attribute to pass parameter in ActionEvent and dlelete selected row

f:attribute tag (JSF Tag supported in ADF Faces) is used to pass some additional attribute value to associated component
Sometimes using f:attribute simplify a complex piece of code, this tag has very simple structure. It has two properties

name- Name of tag attribute
value- Value or an EL reference of value

Here in this post we will see how to use this tag with ADF Faces, I am using Departments table of HR Schema and requirement is to delete departments with attribute DepartmentId  greater than 100


So i have added a link in af:table to delete selected department
Now on this delete link action i have to check that DepartmentId for selected row should be greater than 100 and there are multiple way to do this

1. Get current row of iterator and get DepartmentId from that row
2. Get selected row using getSelectedRowKeys


But here i am using f:attribute to get selected DepartmentId, See how to do this



Add f:attribute tag under af:link like this, here i have assigned #{row.DepartmentId} as value reference of f:attribute tag, this will store selected departmentId in attribute


<af:column id="c5">
                        <af:link text="Delete" id="l1"
                                 actionListener="#{viewScope.FAttributeDemoBean.deleteDepartmentAction}">
                            <f:attribute name="DepartmentId" value="#{row.DepartmentId}"/>
                        </af:link>
                    </af:column>

Now see how to get f:attribute value in managed bean and perform delete operation on that basis


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

import oracle.adf.model.BindingContext;

import oracle.binding.BindingContainer;
import oracle.binding.OperationBinding;


    /**Get BindingContainer of current view port**/
    public BindingContainer getBindingsCont() {
        return BindingContext.getCurrent().getCurrentBindingsEntry();
    }

    /**
     * Generic Method to execute operation Binding
     * */
    public OperationBinding executeOperation(String operation) {
        OperationBinding createParam = getBindingsCont().getOperationBinding(operation);
        return createParam;

    }

    /**Method to delete Department row on condition basis
     * @param actionEvent
     */
    public void deleteDepartmentAction(ActionEvent actionEvent) {
        //Get attribute value using it's name
        Object obj = actionEvent.getComponent().getAttributes().get("DepartmentId");
        if (obj != null && ((Integer) obj) > 100) {
            // If department id is greater than 100 then call delete operation on it
            executeOperation("Delete").execute();
            executeOperation("Execute").execute();
        } else {
            FacesMessage errMsg = new FacesMessage("Department Id for selected Department is not greater than 100");
            errMsg.setSeverity(FacesMessage.SEVERITY_ERROR);
            FacesContext.getCurrentInstance().addMessage(null, errMsg);
        }
    }

All done , Run application and check (tried deleting Department with DepartmentId 100)


Sunday 21 August 2016

Scroll to particular component using af:scrollComponentIntoViewBehavior tag in ADF Faces

You all must have seen HTML Anchor links, this is actually called link within page and used to navigate between page sections
Same as HTML anchor tag ADF Faces has <af:scrollComponentIntoViewBehavior> tag that allows user to jump to a particular component on page

So in this post i am using 5 images and 5 buttons to navigate to each image, set clientComponent property of all af:image to true because this tag is supported only by client rendered components.

Dropped scrollComponentIntoViewBehavior under all buttons and provided id of respective af:image component
See XML source of page -




<af:panelStretchLayout id="psl1" topHeight="25px" bottomHeight="25px" dimensionsFrom="parent">
                    <f:facet name="bottom">
                        <af:panelGroupLayout id="pgl3" layout="horizontal">
                            <af:button text="Paragliding" id="b4">
                                <af:scrollComponentIntoViewBehavior componentId="i1"/>
                            </af:button>
                            <af:button text="Rope Way" id="b5">
                                <af:scrollComponentIntoViewBehavior componentId="i5"/>
                            </af:button>
                        </af:panelGroupLayout>
                    </f:facet>
                    <f:facet name="center">
                        <af:panelGroupLayout id="pgl1" layout="scroll">
                            <af:image source="#{resource['images:1.jpg']}" id="i1"
                                      inlineStyle="width:700px;height:400px;" shortDesc="Paragliding"
                                      clientComponent="true"/>
                            <af:image source="#{resource['images:3.jpg']}" shortDesc="Rope Way" id="i5"
                                      inlineStyle="width:700px;height:400px;" clientComponent="true"/>
                            <af:image source="#{resource['images:2.jpg']}" id="i2"
                                      inlineStyle="width:700px;height:400px;" shortDesc="Green Ground"
                                      clientComponent="true"/>
                            <af:image source="#{resource['images:8.jpg']}" id="i3"
                                      inlineStyle="width:700px;height:400px;" shortDesc="Beautiful Cottage"
                                      clientComponent="true"/>
                            <af:image source="#{resource['images:9.jpg']}" id="i4"
                                      inlineStyle="width:700px;height:400px;" shortDesc="Sheeps"
                                      clientComponent="true"/>
                        </af:panelGroupLayout>
                    </f:facet>
                    <f:facet name="start"/>
                    <f:facet name="end"/>
                    <f:facet name="top">
                        <af:panelGroupLayout id="pgl2" layout="horizontal">
                            <af:button text="Green Ground" id="b1">
                                <af:scrollComponentIntoViewBehavior componentId="i2"/>
                            </af:button>
                            <af:button text="Beautiful Cottage" id="b2">
                                <af:scrollComponentIntoViewBehavior componentId="i3"/>
                            </af:button>
                            <af:button text="Sheeps" id="b3">
                                <af:scrollComponentIntoViewBehavior componentId="i4"/>
                            </af:button>
                        </af:panelGroupLayout>
                    </f:facet>
                </af:panelStretchLayout>

Page looks like this -

Tuesday 16 August 2016

Iterate over master detail viewObject using view link accessor

Here I am using Departments and Employees table of HR Schema to create Master-Detail relation and due to view link relation, Department viewObject has view link accessor of Employees viewObject


This view link accessor containes rows for corresponding row of master (Departments) viewObject, It returns different rowset (list of Employees) for each record of Departments viewObject and we can programmatically access this view link accessor for each master record


Code in AMImpl to Iterate over Master and Detail view object records



import oracle.jbo.Row;
import oracle.jbo.RowSet;
import oracle.jbo.RowSetIterator;
import oracle.jbo.ViewObject;


    /**
     * This is the method to iterate over Departments and corresponding Employees records
     */
    public void iterateMasterDetail() {
        //Get Master ViewObject
        ViewObject deptVo = this.getDepartmentsView();
        //Create iterator to iterate over master viewObject
        RowSetIterator rsi = deptVo.createRowSetIterator(null);

        while (rsi.hasNext()) {
            //Get Master ViewObject Row
            Row departmentsRow = rsi.next();
            System.out.println("Department Name :" + departmentsRow.getAttribute("DepartmentName"));
            //Get Corresponding child viewobject accessor
            RowSet rs = (RowSet) departmentsRow.getAttribute("EmployeesView");

            //Iterate over child viewObject rows for corresponding master record
            while (rs.hasNext()) {
                Row r = rs.next();
                System.out.println("      Employee : " + r.getAttribute("FirstName") + " " +
                                   r.getAttribute("LastName"));
            }
        }
        //Close Master viewObject iterator
        rsi.closeRowSetIterator();
    }

Add this method to client interface of Application Module and Run Application Module to check it

 Output on log

Monday 15 August 2016

Programmatically populate values in a af:selectOneChoice component in ADF

In this tutorial you will see that how to populate selectOneChoice list from managed bean, sometimes we need to use custom list that are not model driven, this scenario can be implemented there

follow steps -

  • First of all create a fusion web application and a page in it
  • Now create a variable of type java.util.List in managed bean, and generate its accessors

  •     List<SelectItem> customList;
    
        public void setCustomList(List<SelectItem> customList) {
            this.customList = customList;
        }
    
        public List<SelectItem> getCustomList() {
            return customList;
        }
    

  • this list contains value of type javax.faces.model.SelectItem; that is supported by af:selectOneChoice
  • now time to add values in list, so to add values in this list i have written this code in getter of variable

  •     public List<SelectItem> getCustomList() {
            if (customList == null) {
                customList = new ArrayList<SelectItem>();
                customList.add(new SelectItem("i1","Item 1"));
                customList.add(new SelectItem("i2","Item 2"));
                customList.add(new SelectItem("i3","Item 3"));
                customList.add(new SelectItem("i3","Item 4"));
                customList.add(new SelectItem("i5","Item 5"));
        }
            return customList;
        }
    

  • Managed bean part is done, now add this to view layer



  • Drop choice list in page from component palette
  •  Now bind choice list to bean List


  • See the page source after whole setup-

  • <?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:af="http://xmlns.oracle.com/adf/faces/rich">
        <jsp:directive.page contentType="text/html;charset=UTF-8"/>
        <f:view>
            <af:document title="listPage.jspx" id="d1">
                <af:form id="f1">
                    <af:panelGroupLayout id="pgl1" layout="vertical" halign="center">
                        <af:spacer width="10" height="10" id="s1"/>
                        <af:selectOneChoice label="Custom List" id="soc1" contentStyle="font-weight:bold;color:darkgreen;">
                            <f:selectItems value="#{ListPolulatebean.customList}" id="si1"/>
                        </af:selectOneChoice>
                    </af:panelGroupLayout>
                </af:form>
            </af:document>
        </f:view>
    </jsp:root>
    

  • Run this page and see programmatic choice list-

Monday 1 August 2016

Range validator Using ADF BC Declarative Built-in Rules

The "Range Validator" is another entity attribute validator which can be be defined at either the entity or attribute level but pertains to an entity attribute just like the "Compare", "Key Exists", "Length" and "List" validators.

As it's name suggests you can use the "Range" validator to ensure that an attribute value falls either within or outside some specified minimum and maximum values. For example, ensure that an employee's salary is between $10,000 and $20,000.

For the purpose of demoing the "Range" validator I have created an ADF Fusion Web Application and created the basic business components that I will be using in this demo; an entity object based on the Employees HR table, a default view object based on the Employees entity object and a default application module.

Next let’s define a "Range" validator on the Employees entity object to ensure that an employee's salary is within a specified minimum and maximum values. So on the  “Business Rules” tab of the Employees entity object, click on the green plus icon “Create new validator”.  This will open the “Add Validation Rule” editor for defining the validation specifics.

In the “Type” combo select “Range”, select the attribute that you want to define the validator, in my demo it's the "Salary" attribute and then select an operator, either Between or NotBetween. In my demo I have selected the "Between" operator.

Under the range section define a minimum and a maximum value.

In the "Failure Handling" tab define a failure message and click "OK". In my example I have used a message token expression to construct a dynamic error message, passing to the failure message the new salary value using the newValue keyword.


If you inspect the Employee’s entity source code you will see that JDeveloper added a RangeValidationBean tag to the XML entity definition file.

Run the Application module to test your "Range" validator and try to update an employee's salary to a value greater than 20,000. The "Range" validator should have fired displaying your error message.

Download sample application: Range Validator

List validator, Using ADF BC Declarative Built-in Rules

The "List Validator" is yet another validator that can be defined at either the entity level or the attribute level but pertains to an entity object attribute to ensure that a value is either in a list or not.

So the "List Validator" compares an attribute against a list of

a) literal values ensuring that the value is in or not in the list of literal values that you define,
b) against an SQL query ensuring that the value is in or not in the first column of the query's result set,
c) against a view attribute ensuring that the value is in or not in the attribute of the specified view object or
d) against a view accessor ensuring that the value is in or not in the specified attribute in all rows of the view object retrieved by the view accessor.

Let's see a demo of the "List Validator". I have created a new ADF Fusion Web Application and created the basic business components that I will be using in this demo, an entity object based on the Departments HR table, a view object based on the Departments entity object and a default application module.


Next let’s define a "List" validator on the Departments entity object to ensure that a department is in the list of literal values that we will define. So on “Business Rules” tab of the Departments entity object, click on the green plus icon “Create new validator”.  This will open the “Add Validation Rule” editor for defining the validation specifics.

In the “Type” combo select “List” and select the attribute on which you want to define the list validator. In my demo I have selected “DepartmentName”. Select the operator (In or NotIn) and the List Type (Literal Values, Query Result, View Object Attribute or View Accessor Attribute). In my demo i have selected the "In" operator and "Literal Values" as the List Type.

In the "Enter List of Values" text box enter the possible values a department can have (enter each values without quotes on a new line).
In the "Failure Handling" tab define a failure message and click "OK". In my example I have used a message token expression to construct a dynamic error message, passing to the failure message the department name.

If you inspect the Department’s entity source code you will see that JDeveloper added a ListValidationBean tag to the XML entity definition file.
Before testing our validator please ensure that your application module has the Departments view selected under the “Data Model”.

To test your validator, run the Application module and try to update a department's name to "Sales" (if you recall i did not include sales in my list of allowed literal values). You should get your custom dynamic error message displayed.

Please note that list validators based on SQL queries or View Object attributes retrieve all rows of a query each time a validation is perform, therefore you should be very careful when you choose to use these list types. It it recommended that you use these list types only for relatively small value sets.

Download sample application: List Validator

Contact Me

Name

Email *

Message *