Wednesday, June 9, 2021

Oracle ADF: af:query hide Add Fields button

Requirement-In Oracle ADF we use af:query along with resulting table in advance mode.When use  af:query in advance mode the UI is displayed as something like below. Usually clients dont want add fields option in advance search as it has all fields that doesn't makes sense to user.

Unfortunately there is no attribute in af:query components that allows us to remove this button.

Screenshot with add field option .








Now to hide this add fields button do below steps

1.Take the Id of Add field button using inspect element in browser .In my case id was "pt1:r2:0:qryId2:adFlds".It will vary based on id of query component and page you are using.















2.At the end of jsff file create a output text that has no next and creating component  binding in backing bean as below.

Please note this need to be at the end of jsff file so that it is rendered at the last in lifecycle.





In Getter method of above created binding right code to get the add fields button component using java script by component id we got in step 1 .Once you find the component set display =none to hide the add fields button.

Backing bean code,as shown below i have written hideAddFieldSection method.


Now if you run the page again you dont see add fields button .Hope this helps






Friday, June 4, 2021

Error: [ADF security error] -while adding transient expression in ADF 12c

In ADF 12c when we want to have transient expression in entity object for example primary key of Entity object is coming from DB sequence then we declare the expression as shown in below

(new oracle.jbo.server.SequenceImpl("SEQUENCE_NAME", adf.object.getDBTransaction())).getSequenceNumber()






















After this if you compile the project you get below error

Error(10,1): [Static type checking] - [ADF security error] Calling the constructor for class oracle.jbo.server.SequenceImpl is not permitted.
 @ line 10, column 1.


Which means that the entity is not trusted the expression changes. To solve this follow below steps

1.Go to the source of the entity object xml file 

2. go to  "TransientExpression" of the attribute which you are adding expression as shown in      screenshot   below 

3.Check the value of the attribute "trustMode"

4.By default  it is "untrusted", change it to "trusted" or remove it

Now recompile the project. Compiler issue doesn't occur








hope this helps

Monday, May 31, 2021

Consume Rest Service Using GSON jar

I am going to demonstrate how to consume rest API service Using Google Json jar that GSON jar .First you need to down the GSON jar .I am using gson-2.8.6.jar for my demo.

Rest service that i am is hosted at http://localhost:8080/employees .when hit GET request to this in postman or in browser i get response as below.

Response-

{

    "employeeList": [

        {

            "employeeId": "1234",

            "employeeName": "Dhiraj Shigavi",

            "departmentName": "Information technology"

        },

        {

            "employeeId": "7777",

            "employeeName": "John Den",

            "departmentName": "Electronic andtele communication"

        }

    ]

}


To Consume this in java follow below steps.
1. create java project in jdeveloper ( you can user any IDE of your choice).
2.add the GSON jar file downloaded in project properties as below



3. Create java Class and name it ConsumeRestServiceWrapper.java.
4. Now first we need to understand the response and create java equivalent classes of  it so we can parse the response using Gson jar file

In this case my response contains employeeList which is list so i will create a class which contains list object of employeeList ,now type of List object contains employeeId,employeeName,departmentName so will create another class which will have these three names of String object in as below.
So My Employee Class is as below.
 
public class Employee {
    private String employeeId;
    private String employeeName;
    private String departmentName;

    public Employee(String employeeId, String employeeName, String departmentName) {
        this.employeeId = employeeId;
        this.employeeName = employeeName;
        this.departmentName = departmentName;
    }
    public String getEmployeeId() {
        return employeeId;
    }
    public void setEmployeeId(String employeeId) {
        this.employeeId = employeeId;
    }
    public String getDepartmentName() {
        return departmentName;
    }
    public void setDepartmentName(String departmentName) {
        this.departmentName = departmentName;
    }
   public String getEmployeeName() {
        return employeeName;
    }
    public void setEmployeeName(String employeeName) {
        this.employeeName = employeeName;
    }
    public Employee() {
        super();
    }
}
My EmployeeResponse class will contain List<Employee>  with name employeeList. 
Please note here name has to match with name in your rest response.
import java.util.List;
public class EmployeeResponse {
    List<Employee> employeeList;
    public EmployeeResponse() {
        super();
    }
    public void setEmployeeList(List<Employee> employeeList) {
        this.employeeList = employeeList;
    }
    public List<Employee> getEmployeeList() {
        return employeeList;
    }
}
















Now main part is to write method in service wrapper class which will call the service and populate the data in object of EmployeeResponse class.
I have written getEmployees method which returns me object of EmployeeResponse created above.
Please note below line which populated the String response into Object that we can use in object format

EmployeeResponse employeeResponse = new Gson().fromJson(response.toString(), EmployeeResponse.class);






























package com.service;

import com.google.gson.Gson;
import com.payload.Employee;
import com.payload.EmployeeResponse;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class ConsumeRestServiceWrapper {
    public ConsumeRestServiceWrapper() {
        super();
    }

    public static void main(String[] args) {
        ConsumeRestServiceWrapper service = new ConsumeRestServiceWrapper();
        try {
            EmployeeResponse response = service.getEmployees();
            if (response != null) {
                if (response.getEmployeeList() != null && response.getEmployeeList().size() > 0) {
                    System.out.println("Employee  list");
                    System.out.println("*****************");
                    for (Employee e : response.getEmployeeList()) {
                        System.out.println("Employee Id-" + e.getEmployeeId());
                        System.out.println("Employee Name-" + e.getEmployeeName());
                        System.out.println("Employee Department-" + e.getDepartmentName());
                        System.out.println("*****************");
                    }

                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    public EmployeeResponse getEmployees() throws Exception {

        URL url = new URL(null, "http://localhost:8080/employees", new sun.net.www.protocol.http.Handler());
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.setDoOutput(true);
        conn.setRequestProperty("Content-Type", "application/json");

        int responseCode = conn.getResponseCode();
        System.out.println("URL...: " + url + "  Response Code..: " + responseCode);
        if (responseCode >= 200 && responseCode < 300) {

            BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
            String line;
            StringBuffer response = new StringBuffer();
            while ((line = br.readLine()) != null) {
                response.append(line);

            }
            br.close();
            System.out.println("Rest response for employee is -" + response);

            EmployeeResponse employeeResponse = new Gson().fromJson(response.toString(), EmployeeResponse.class);


            return employeeResponse;
        } else {
            BufferedReader in = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
            String line;
            StringBuffer errorResponse = new StringBuffer();

            while ((line = in.readLine()) != null) {
                errorResponse.append(line);
            }
            in.close();
            throw new RuntimeException(conn.getResponseCode() + " Invalid Response " + errorResponse);
        }

    }
}


when i run above class i get response as below















Some of rest service response just contains the list without the name as below

























In this case when you run above code ,you would get exception as com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $

so change the line in getEmployees method as below and it will directly populate in List<Employee>

List<Employee> employeeResponse = new Gson().fromJson(response.toString(), List.class);




hope this helps to know how to consume rest API using Gson jar file.

Wednesday, May 26, 2021

ADF dropdown Adjusting width with af:panelFormLayout

In ADF width of af:selectOneChoice is adjusted to fit its content and sometime we dont want that to happen specifically when we use af:panelFormLayout with multiple input components like af:inputText af:selectoneChoice.

In this example i am using below code 











My UI Looks like Below and you can see dropdown is not align with input textbox.










To align this af:selectOneChoice with af:inputText set  contentStyle="width:100%;"  of af:selectOneChoice as shown below






With this your dropdown will be aligned as below



Sunday, May 23, 2021

Call Stored procedure with Array as input parameter from java

Requirement-It is very common requirement to call stored procedure which takes array as input parameter. In below example i am calling the stored procedure from Impl class of application module.

My procedure is having String of array as second parameter.When we want to pass String of array to Stored procedure we need to convert this String of array to Sql array type.For this we need below two things 

  1. The array that we pass should be declared in data as type in database as shown in below CST_LTG_ARRAY_VARCHAR2 is declared as type in database.Same type will be used in stored procedure input parameter as shown in screenshot 2
  2. We need to convert the java.sql.Connection to oracle.jdbc.OracleConnection object as shown in code snippet
Now use this OracleConnection reference to create array reference that we need to pass to stored procedure using below line.Remember minute details here -dont forget to mention schema name dot your type name in database in all uppercase otherwise code will throw java.sql.SQLException: invalid name pattern.


       Array subSetCodesArray = oraConn.createARRAY("EL_EGWH_EXT_WORK.CST_LTG_ARRAY_VARCHAR2", subSetCodes);

Now final step is to pass this subSetCodesArray  array to callableStatement setArray method as below

 statement.setArray(2, subSetCodesArray);


Final method looks like below initializeDataSource is methd used to get connection reference from dataSource in weblogic server.

    public String callApplyClusterStoredProcedure(Long batchNumber, String[] subSetCodes) {


        DBTransactionImpl dbtrx = (DBTransactionImpl) getDBTransaction();

        CallableStatement statement =

            dbtrx.createCallableStatement(("BEGIN " + "SCHEMA_NAME.PROCEDURE_NAME(?,?,?,?);" + "END;"), 0);

        try {

            DataSource ds = initializeDataSource();

            java.sql.Connection conn = ds.getConnection();

            OracleConnection oraConn = conn.unwrap(OracleConnection.class);

            statement.setLong(1, batchNumber);

            if (subSetCodes != null) {

                Array subSetCodesArray = oraConn.createARRAY("EL_EGWH_EXT_WORK.CST_LTG_ARRAY_VARCHAR2", subSetCodes);

                statement.setArray(2, subSetCodesArray);

            } else {

                //use below code to set Null if array is empty or null

                statement.setNull(2, java.sql.Types.ARRAY,"EL_EGWH_EXT_WORK.CST_LTG_ARRAY_VARCHAR2");

            }


            statement.registerOutParameter(3, java.sql

                                                  .Types

                                                  .VARCHAR);

            statement.registerOutParameter(4, java.sql

                                                  .Types

                                                  .VARCHAR);

            statement.execute();

            //Long balanceToInclude = statement.getLong(4);

            String result = statement.getString(3);

            String message = statement.getString(4);

            System.out.println("result -" + result);

            System.out.println("message-" + message);

            return result;

        } catch (SQLException sqlerr) {

            throw new JboException(sqlerr.getMessage());

        } finally {

            try {

                if (statement != null) {

                    statement.close();

                }

            } catch (SQLException closeerr) {

                throw new JboException(closeerr.getMessage());

            }

        }

    }


    private DataSource initializeDataSource() {

        InitialContext ctxt = null;

        DataSource dataSource = null;

        try {

            ctxt = new InitialContext();

            dataSource = (DataSource) ctxt.lookup("jdbc/EgwhDS");

            ctxt.close();

        } catch (Exception e) {

            e.printStackTrace();

        }

        return dataSource;

    }

Thursday, May 20, 2021

ADF view object with bind parameter and like operator .

 Requirement:

In this post i am explaining how to create ADF view object with like operator and bind parameter in where clause. requirement is very simple get all rows from employee table with employee containing runtime value entered by user.


In this case while we create new object in Jdeveloper give query as below

Query here is -


select EMPLOYEE_NAME,EMPLOYEE_ID from EMPLOYEE 

where  ( (UPPER(EMPLOYEE_NAME) LIKE UPPER('%' || :pEmployeeName || '%') )
















In the next screen give bind parameter pEmployeeName of type string as below














After this pass the bind parameter from UI as user entered value .Hope this helps

Saturday, March 27, 2021

Oracle Cloud Infrastructure 2020 Certified Architect/1Z0-1072-20 -EXAM questions/Dump

 HI All,

Recently i passed the exam for Oracle Cloud Infrastructure 2020 Certified Architect. Its tough exam with 60% passing percentage.

Attached are exam dump questions that i got along with answers for each. You will definitely pass the exam with only following the document questions


click link for Dump questions and answers

All the Best :)

Friday, March 12, 2021

ADF table -Achieve case insensitive sort for af:column

 In Oracle ADF when we use sortable="true" on af:column By default sorting will be done case-sensitively ,which means that upper case data will be shown first and then lower case data will shown .As shown in below screenshot






,









To make this work case insensitively , we can use sortStrength="Primary" attribute on af:column as below






Now my work works case insenstive as below.














Please note this works only with 11.1.1.7 and above version

Wednesday, March 10, 2021

Setting NULL value using af:setPropertyListener in ADF

 Usually we come across common requirement to set value of session scope or pageFlowScope variable to NULL on click of adf button or  af:commandLink to do this you can af:setPropertyListener inside af:commandLink as below and use EL as #{null}

<af:commandLink text="Clear">

            <af:setPropertyListener  from="#{null}"

                                                  to="#{sessionScope.userName}"

                                                   type="action"/>

</af:commandLink>


in above case i am setting userName to null.

Tuesday, March 9, 2021

Reset ADF table filters programmatically

Requirement-When we use ADF table i.e af:table with filters on each column ,It is very common requirement to clear filter data and reset table result to its initial state.

One way to do is to add af:column as first column in af:table and set rowHeader="true" attribute in af:column.This will show icon in first column to clear filter and reset table results.


There may be a requirement to do this on click of button which is outside af:table .So in this case add below code in button actionListener.



    public void backActionListener(ActionEvent actionEvent) {

        // Add event code here...

        FilterableQueryDescriptor fqd = (FilterableQueryDescriptor)deleteUserTableBinding.getFilterModel();

                      if (fqd != null && fqd.getFilterCriteria() != null) {

                        fqd.getFilterCriteria().clear();

                        deleteUserTableBinding.queueEvent(new QueryEvent(deleteUserTableBinding, fqd));          

                       

                     }

    }

Note: deleteUserTableBinding is my af:table component binding name.(change as per yours)

This will work as long as you are on same page on click of reset button in my case i call it back button. But if are redirecting to different jsff or jspx on click of your reset button above code will throw error saying binding not found because on the page which you are redirecting to does not have table binding iterators and tree binding .


Solution to solve this problem is go to first page's page defination file and copy tree binding and iterator binding ,now paste this in page defination file of next page which you are redirecting to so when we queue event in above code snippet it will find the required binding and wont throw exception.


Monday, March 8, 2021

ADF table- case Insensitive search on column filter of af:table

when we add table filters to ADF table the filter is case sensitive by default and common requirement is to have case insensitive filter.

Solution for this is very simple -Set af:column attribute filterFeatures="caseInsensitive"


and filter will work case insensitive.

Saturday, March 6, 2021

ADF LOV based dropdown not showing all records

 It is very common requirement to show dropdown with values coming database .In ADF we use Model based LOV dropdown or we drag the View object as af:selectOneChoice in our fragment or jspx page as below



now code that gets generated is as below








When you run this page the dropdown that is shown is just having 10 values as below















Where as in Database  i have 27 department names present .Reason for having 10 records in dropdown is if you go to page definition file of above dropdown page it looks like below and iterator binding of the DepartmentView is having range size as 10










Now to see all records of department names present in database change the range size 

value to -1 and run the page again to see dropdown show all values of department name as below .



Tuesday, March 2, 2021

Change Default look or CSS of ADF button

 Requirement-It is very common requirement in any adf application to change the default color of adf button,adf button text color as per client requirement of UI design.


when we use af:commandButton in 11g or af:button component in 12c it comes with default look as below.









Now requirement is to change the default look to something else as per your project standards so that we dont have to apply inline style each time we use adf button in application.

In my case I converted it to green background color with text color white.

Add below snippet of css in you ADF application css file and run the application again to see new look and feel of default button.


Code Snippet in CSS

.af_commandButton.p_AFTextOnly,

.af_commandButton, button.af_commandButton,button,button:focus,.af_commandButton:focus,.af_commandButton:active:hover,.af_commandButton:focus:hover.af_commandButton:focus:active,.af_commandButton:active:focus{

  background: #40A828 !important;

  text-decoration: none ;

  color:#ffffff !important;

  padding:3px 10px 3px 10px !important;

  border:none  !important;

  border-style: none !important;

  outline:none !important;

  cursor: pointer;

}

New button look will be something like below.Now just just af:commandbutton component anywhere in application and button color will be as below.










you can also have two three types of button css in you application but for that different style class need to be created.

Sunday, August 2, 2020

OIM ADF Customization-Adding ADF custom taskflow

Requirement:In OIM ADF customization very common requirement is to open new custom taskflow on click of icon. Follow below steps to achieve it in OIM. 

1.   Export the sandbox and unzip it.

2.    Open the Home page jsff.xml file that you are working on by using a text editor. Oracle Identity Manager has the following default Home pages for Self Service, Manage, and Compliance:

oracle/iam/ui/homepage/home/pages/mdssys/cust/site/site/self-service-manage.jsff.xml

3.    Locate the oim:DashboardBox element in the XML file. The element looks similar to the following: 

<oim:DashboardBox xmlns:oim="/componentLib1" instructionText="My user details" titleText="My Details" image="/images/Dashboard/myAccess.png" hoverImage="/images/Dashboard/myAccess_s2.png" iconClickable="true" id="e8533237995"/>

4.    Ensure that the value of iconClickable is set to true.

5.    Add a new element attribute named iconClickAction, set the value of the attribute to:

#{backingBeanScope.dashboardNavigationBean.launchTaskFlow}

6.    Add two new af:clientAttribute elements as child elements of oim:DashboardBox, as follows:

  <oim:DashboardBox xmlns:oim="/componentLib1" instructionText="Manage profiles" titleText="Profile Management" image="/images/Dashboard/myAccess.png" hoverImage="/images/Dashboard/myAccess_s2.png" iconClickable="true" id="e8381776527" iconClickAction="#{backingBeanScope.dashboardNavigationBean.launchTaskFlow}">

          <af:clientAttribute xmlns:af="http://xmlns.oracle.com/adf/faces/rich" xmlns:f="http://java.sun.com/jsf/core" name="taskFlowId" value="/WEB-INF/oracle/iam/ui/custom/profile-management-tf.xml"/>

            <af:clientAttribute xmlns:af="http://xmlns.oracle.com/adf/faces/rich" name="title" value="Profile Management"/>   

          </oim:DashboardBox>

 Please note that in above code xmlns:f="http://java.sun.com/jsf/core"  is very important as i am using faces components it is important to add that in af:clientAttribute .My taskflow jsff is as follows.

    <?xml version='1.0' encoding='UTF-8'?>

    <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1" xmlns:af="http://xmlns.oracle.com/adf/faces/rich"

          xmlns:f="http://java.sun.com/jsf/core" xmlns:c="http://java.sun.com/jsp/jstl/core">

    <c:set var="BTExtensionBundleUI" value="#{adfBundle['ro.bt.adf.view.bundle.BTExtensionBundle']}"/>

    <af:outputText value="Profile Management" id="ot1"/>

    </jsp:root>

Make sure that oim:DashboardBox now has opening and closing tags, as shown in the example. Also, ensure that the component IDs are unique.

Set values of taskFlowId and title client attributes. taskFlowId specifies which task flow will be launched, and title specifies the title of the new tab. 

7.       Save the jsff.xml file, and re-create the sandbox ZIP file with the same name and structure as the original ZIP file.

8.       Import the sandbox to Oracle Identity Manager.

9.       Verify the changes and functionality of the new Home page tile.

10.     Export the sandbox and publish it to make the changes available to all users.

New Icon when clicked new taskflow opens in new tab as below