Posts Tagged 'ADF'

Adding Code Source grants from EM

Often there is a need to interact with credential or policy store from java/ADF code which requires code source grants/system policies. Typically the application’s jazn file will have these values like the following.


<grant>
<grant>
<grantee>
<codesource>
<url>file:${domain.home}/servers/AdminServer/upload/HumanTaskApiTestService/-
</codesource>
</grantee>
<permissions>
<permission>
<class>oracle/security/jps/service/credstore/CredentialAccessPermission
<name>context=SYSTEM,mapName=admin/security,keyName=ADMIN_KEY</name>
<actions>read</actions>
</permission>
<permission>
<class>oracle.security.jps.service.policystore.PolicyStoreAccessPermission</class>
<name>context=APPLICATION,name=*</name>
<actions>*</actions>
</permission>
</permissions>
</grant>
</grant>

Use the following steps to provide these grants through EM Console.

Login to EM Console and navigate to Weblogic Domains -> <> -> Security (on right click) -> System Policies

create

grant

grant1.jpg

grant2

Advertisement

ADF BC REST Services Articles

Sample application can be found here.

ADF BC REST Services–III – Using Row Finder

In this post, we will see how to use Row Finder in ADF BC REST services.

Open REST resource VO and create a View Criteria as shown below having 2 bind variables for Department name and Location ID.

vc

vc1

Go to Row Finders section and create new one with searhByDeptName.

rf0

Here we can observe that above VC is selected by default. In Variables section as shown below, we can also set whether bind variable is allowed to be passed in REST resource URL along with Required settings.

rf

Deploy the application and use any REST client to test GET method using the following urls. Observe the usage of row finder and bind variables.

Passing single bind variable:

http://localhost:7001/departmentApi/rest/r1/departments?finder=searchByDeptName;bindDeptName=A

Passing both bind variables:

http://localhost:7001/departmentApi/rest/r1/departments?finder=searchByDeptName;bindDeptName=A,bindLocId=1800

Now mark bindLocId variable as required and try to test without using it in the URL and you will observe the error as shown below.

error

ADF BC REST Services–II – Change Indicator

In ADF, often we see error saying ‘JBO-25014: Another user has changed the row with primary key oracle.jbo.Key’. The framework throws this error to make sure that none of the user changes are accidentally overwritten by another user and generally occurs when a user trying to modify record that has been just modified and committed by another user. In this post, we will see how to take care of this scenario using ADF BC REST services in context of HTTP PATCH.

ADF BC REST Services make use of attribute called changeIndicator  which can be observed in response of GET.

Follow the steps mentioned below to enable this in a resource:

  • EO should have an attribute marked as Change Indicator and set Track Change History as shown below.

ovn

  • Add this attribute in VO i.e to be exposed as REST resource.

ovnvo

Deploy your changes and issue GET to observe changeIndicator as below.

get

cin

for e.g. changeIndicator for department 10 (resource instance):

ACED0005737200136A6176612E7574696C2E41727261794C6973747881D21D99C7619D0300014900047
3697A65787000000001770400000001737200116A6176612E6C616E672E496E746567657212E2A0A4F7
81873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08
B02000078700000000178

Now update department 10 using following sql query to simulate the actual update.

update departments set department_name = ‘Administration-modified’, object_version_number = object_version_number+1
where department_id = 10

Issue GET again on same resource and observe the changeIndicator.

ACED0005737200136A6176612E7574696C2E41727261794C6973747881D21D99C7619D0300014900047
3697A65787000000001770400000001737200116A6176612E6C616E672E496E746567657212E2A0A4F7
81873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08
B02000078700000000378

 

cin1

As observed above, the value of changeIndicator changes with each update and is calculated by RESTServlet registered in web.xml of RESTWebService project.

restsvlt

Here is an interesting observation and do issue issuing GET for department 10.

http://localhost:7001/departmentApi/rest/r1/departments/10

If we observe HTTP response headers, the value of ETag is same as that of changeIndicator. Hence changeIndicator works in similar lines of ETag defined in HTTP specification.

etag

Now let us observe the behavior of REST resource when  ETag is used for If-Match/If-None-Match HTTP headers during GET and PATCH. Basically these HTTP headers tells server to do requested operation when sent Etag value matches or did not match respectively.

Make sure you enclose ETag value with “ (double quotes) as shown below.

If-None-Match:

Using GET:

  • When resource is not modified, returns status code as 304.

getnonematch

  • When resource is modified, returns response with new changeIndicator value.

getnonematch1

Using PATCH:

  • When resource is not modified, returns response status code as 412.

patchnonematch

  • When the resource is not modified, then returns response with new changeIndicator value after update.

patchnonematch1

If-None-Match

Modified

Not Modified

GET

Status:200
(Query Successful)
Status: 304

PATCH

Status: 200
(Update Successful)
Status: 412

If-Match:

Using GET:

  • When resource is not modified, resource is returned.

getmatch1

  • When resource is modified, expected response status code is 304 but shows 200 with junk response.

getmatch3

Using PATCH:

  • When resource is not modified, returns response with new change Indicator value after update.

getmatch2

  • When resource is modified, expected response status code is 412 but shows 200 with junk response. However you will observe that the actual update is not happening though it returns 200.

patchmatch1

If-Match

Modified

Not Modified

GET

Status:304 Status:200
(Query Successful)

PATCH

Status:412 Status: 200
(Update Successful)

Note: As you observed above, ETag combination with If-Match header is not working as expected which is a bug in this release.

References:

http://docs.oracle.com/middleware/1221/adf/develop/GUID-589F3905-5A8D-402D-B2D2-3BEEB2D7DDD4.htm#ADFFD54158

ADF BC REST Services-I

In this blog post, We will see how to expose ADF VOs as REST resources. ADF has got native REST support in 12.2.1 release.

We will use Department, Employee VOs and following AM Data Model here.

vos

am

Creating Release Version:

Creating a release version in adf-config.xml is the first step to be done before exposing any of the AM VOs as resource. Use the following steps to create one and you can follow your own conventions for versioning REST resources. Here I  have given the initial version as r1.

relversion

rel1

relactive

Expose VO as REST resources:

Open AM and navigate to Web Service –> REST and Click + icon.

restampage

Creation of REST resources create a new project RESTWebService.jpr in our workspace that can be deployed as WAR through which these REST services get deployed.

restws

Give the resource name as shown below and click OK.

createrest

Observe the new RESTWebService project gets created.

restws1

Also observe other files related to REST resources that get created as shown below.

files

You can use the following tabs to choose the methods to be exposed and the attributes to be exposed to consumers.

attr

When a VO has View Links the Resource Structure will show all these VOs as shown below. Check these VOs as shown below if it has to be exposed as child resource.

restdetail

Deployment:

Modify context root of RESTWebService project as shown below representing the purpose of your REST API.

deptApi

Optionally, we can modify URL pattern in web.xml as shown below.

urlp

Integrated WLS:

Select RESTWebservice project and do Run on right click as shown below.

runintg

Standalone WLS:

Create EAR profile for ADF application and include RESTWebService project as shown below and deploy this EAR to standalone WLS.

ear

Once the deployment is done, you can access the REST resource using url like:

http://<<host>&gt;:<<port>>/<<ContextRoot>>/<<url pattern>>/<<version>>/<<resource name>>

For e.g.: http://localhost:7001/departmentApi/rest/r1/departments

We can also use latest keyword to access the latest version of the resource.

For e.g.: http://localhost:7001/departmentApi/rest/latest/departments

You can use any REST client to try out POST, DELETE, PUT, PATCH depending on the operations you exposed on REST resource.

Describing Resource – GET:

URI: http://localhost:7001/departmentApi/rest/r1/departments/describe

Describing Resource Instance – GET:

URI: http://localhost:7001/departmentApi/rest/r1/departments/10/describe

 

Querying Departments – GET:

URI: http://localhost:7001/departmentApi/rest/r1/departments

Querying a particular Department – GET:

URI: http://localhost:7001/departmentApi/rest/r1/departments/{id}

Creating Department – POST:

URI: http://localhost:7001/departmentApi/rest/r1/departments

Content-Type: application/vnd.oracle.adf.resourceitem+json

Body:

{
“DepartmentId”: 1000,
“DepartmentName”: “Administration”,
“ManagerId”: 200,
“LocationId”: 1700
}

Deleting a Department – DELETE:

URI: http://localhost:7001/departmentApi/rest/r1/departments/{id}

Updating a Department – POST:

URI: http://localhost:7001/departmentApi/rest/r1/departments/{id}

Content-Type: application/vnd.oracle.adf.resourceitem+json

X-HTTP-Method-Override: PATCH

Body: (contains only fields to be modified)

{
“DepartmentName”: “Administration-Modified”
}

Replacing a Department – PUT:

URI: http://localhost:7001/departmentApi/rest/r1/departments/{id}

Content-Type: application/vnd.oracle.adf.resourceitem+json

Body: (Values not sent in body will be set to null)

{
“DepartmentId”:10,

“DepartmentName”: “Administration-Replace”,
“ManagerId”: 100
}

Querying Department for a few fields – GET:

URI: http://localhost:7001/departmentApi/rest/r1/departments?fields=DepartmentName,ManagerId

Querying a Department using an attribute – GET:

URI: http://localhost:7001/departmentApi/rest/r1/departments/{id}?q=DepartmentName=Administration

Querying a Department for only Data – GET:

URI: http://localhost:7001/departmentApi/rest/r1/departments?onlyData=true

Will not fetch any links or  metadata for resource instances in response.

Sorting Departments – GET:

URI: http://localhost:7001/departmentApi/rest/r1/departments?orderBy=DepartmentName:asc

URI: http://localhost:7001/departmentApi/rest/r1/departments?orderBy=DepartmentName: desc

Limiting the records in Querying Departments – GET:

URI: http://localhost:7001/departmentApi/rest/r1/departments?limit=2

Fetches only 2 records.

Querying Departments from a particular record– GET:

URI: http://localhost:7001/departmentApi/rest/r1/departments?offset=2

Fetches only 2 records.

URI: http://localhost:7001/departmentApi/rest/r1/departments?offset=2&limit=5

Fetches 5 records starting from 2nd record.

Expanding a Child Resource – GET:

URI: http://localhost:7001/departmentApi/rest/r1/departments?expand=Employee (Child Resource Name)

Querying Child Resource – GET:

URI: http://localhost:7001/departmentApi/rest/r1/departments/{id}/child/Employee

Querying a particular Child Resource – GET:

URI: http://localhost:7001/departmentApi/rest/r1/departments/{id}/child/Employee/{Child Resource Id}

Querying a Child Resource using an attribute – GET:

URI: http://localhost:7001/departmentApi/rest/r1/departments/{id}/child/Employee?q=FirstName=Jennifer

References:

http://docs.oracle.com/middleware/1221/adf/develop/GUID-8F85F6FA-1A13-4111-BBDB-1195445CB630.htm#ADFFD589

http://docs.oracle.com/middleware/1221/adf/develop/GUID-589F3905-5A8D-402D-B2D2-3BEEB2D7DDD4.htm#ADFFD54082

ADF–Using bind variable with IN clause

Using IN clause is very common requirement when working with the ADF View Objects and rows have to be filtered on multiple values of the same attribute.

In this blog, Jobinesh shows a way to achieve this requirement using the bind variable. The same approach is not working when we have to use the multiple columns in IN clause like below:

                     select * from tableA where (col1,col2,col3) IN ()

We can use the following code to achieve this and have tested in ADF 11g.


import oracle.jbo.domain.Array;
import oracle.jbo.domain.DomainContext;
import oracle.sql.ArrayDescriptor;
import oracle.sql.STRUCT;
import oracle.sql.StructDescriptor;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/* create the DB object and table as below
create or replace TYPE DB_OBJECT AS OBJECT(
destcol1 varchar2(100 char), destcol2 number,destcol3 varchar2(100 char),destcol4 number );
create or replace TYPE DB_TABLE AS TABLE OF DB_OBJECT;
*/
public void setVOArrayBindVariable(){
Connection conn = null;
PreparedStatement stmt = null;
StructDescriptor structDescriptor = null;
ArrayList<STRUCT> arrayList = new ArrayList<STRUCT>();
try{
stmt = getDBTransaction().createPreparedStatement("select 1 from dual", 0);
conn = stmt.getConnection();
structDescriptor = StructDescriptor.createDescriptor("DB_OBJECT",conn);
//loop through and populate your arrayList with the values to be used in IN clause
for (int j = 0; j < 10; j++) {
// constucting the Object to create struct definition
Object[] o = new Object[]{getValue1(), getValue2(),getValue3(),getValue4()};
STRUCT item = new STRUCT(structDescriptor,conn,o);
conn.createStruct("DB_OBJECT", o);
arrayList.add(eventRowStruct);
}
if(eventDataIdList.size() > 0){
ArrayDescriptor tableArray = ArrayDescriptor.createDescriptor("DB_TABLE", conn);
Array domainArray = new Array(tableArray,conn,arrayList.toArray());
//set the bind variable. your VO should have bind variable of type oracle.jbo.domain.Array
vo.setbindEventDetailArray(domainArray);
//execute the query
vo.executeQuery();
}
} catch (SQLException sqlex) {
//do log the error
} catch (Exception ex) {
//do log the error
} finally {
try {
stmt.close();
} catch (SQLException sqlex) {
//do log the error
}
}
}
/* your getCriteriaItemClause() code look like below */
public String getCriteriaItemClause(){
//do the following only for your VC and VC item. details are omitted here
String whereClause = "(1=1)";
String eoName = this.getEntityDef(0).getAliasName();
if(getbindDomainArray() != null){
whereCluase =
" (" +eoName + ".col1,"+eoName + ".col2,"+eoName + ".col3,"+ eoName+".col4)" +
" IN (SELECT destcol1, destcol2, destcol3, destcol4 FROM TABLE(:bindDomainArray))";
}
return whereClause;
}

How-To: Populate PL/SQL Collections in ADF Code

People tend to write lot of business logic in PL/SQL when there is lot of data to manipulate with or to improve the performance. When PL/SQL collections are the best way to accept multiple records as input and return the response.

This post shows the sample code to call a PL/SQL API accepting PL/SQL table from an ADF application module.

PL/SQL Objects:

CREATE OR REPLACE TYPE emp_rec_type AS OBJECT (
    employee_id     NUMBER(18),
    first_name      VARCHAR2(30),
    last_name       VARCHAR2(30),
    middle_name     VARCHAR2(30),
    employee_type   VARCHAR2(30),
    location        VARCHAR2(30),
    addr_line1      VARCHAR2(30),
    addr_line2      VARCHAR2(30),
    addr_line3      VARCHAR2(30)
    city            VARCHAR2(30)
);

CREATE OR REPLACE TYPE emp_tbl_type AS TABLE OF emp_record;

CREATE OR REPLACE PACKAGE emp_ddl_package AS
   PROCEDURE validate_emp_records (
      emp_rec_list        IN OUT NOCOPY emp_tbl_type,
      validation_status OUT NOCOPY VARCHAR2     
    );
END emp_ddl_package;

CREATE OR REPLACE PACKAGE BODY emp_ddl_package AS 
 
  PROCEDURE validate_emp_records(
      emp_rec_list IN OUT NOCOPY emp_tbl_type,
      validation_status OUT NOCOPY VARCHAR2
  )IS   
  BEGIN 
          — do the coding here
  END validate_emp_records;
END emp_ddl_package;

 

Sample Code of Java Method in Application Module:

Following is the typical piece of code that can be used in ADF application module to call the PL/SQL API:

public List<EmpVORowImpl> validateEmployees(List<EmpVORowImpl> empList) throws Exception {
  OracleCallableStatement stmt = null;
  ArrayList<EmpVORowImpl> empRespList = null;

  if (empList != null && empList.size() > 0) {
         empRespList = new ArrayList<EmpVORowImpl>();

    try {
      // Call the pl/sql API to determine invoice status
      String sql = 
"begin emp_ddl_package.validate_emp_records(emp_rec_list=>:1,validation_status=>:2); end;";

      stmt =
          (OracleCallableStatement)getDBTransaction().createCallableStatement(sql,0); 
ArrayList<STRUCT> inputEmpList  = new ArrayList<STRUCT>();

StructDescriptor structDescriptor = StructDescriptor.createDescriptor(“EMP_REC_TYPE”,stmt.getConnection());

  for (int i = 0; i < empList.size(); i++) {
        EmpVORowImpl empRow = empList.get(i);
        Object[] o =
          new Object[] { empRow.getEmployeeId(), empRow.getFirstName(),
                         empRow.getLastName(), empRow.getMiddleName(),
                         empRow.getEmployeeType(), empRow.getLocation(),
                         empRow.getAddrLine1(), empRow.getAddrLine2(),
                         empRow.getAddrLine3(), empRow.getCity() };

        STRUCT empRowStruct = new STRUCT(structDescriptor,stmt.getConnection(), o); 
        inputEmpList.add(empRowStruct);

      }

      ArrayDescriptor empArray =
        ArrayDescriptor.createDescriptor("EMP_TBL_TYPE",
                                         stmt.getConnection());
      ARRAY empArrayTbl =
        new ARRAY(empArray, stmt.getConnection(), inputEmpList.toArray());

      stmt.registerOutParameter(1, OracleTypes.ARRAY, "EMP_TBL_TYPE");
      stmt.setARRAY(1, empArrayTbl);
      stmt.registerOutParameter(2, OracleTypes.VARCHAR, 0, 1);
      stmt.execute();

      //get the output table from pl/sql API and return
      Array outputArray = stmt.getArray(1);
      String returnStatus = stmt.getString(2);

      if (returnStatus != null && "Success".equals(returnStatus) &&
          outputArray != null) {
        ResultSet rs = outputArray.getResultSet();
        EmpVORowImpl tempRow;

        while (rs != null && rs.next()) {
          Struct empRespStruct = (Struct)rs.getObject(2);
          Object[] empAttributes = empRespStruct.getAttributes();

          if (empAttributes != null) {
            tempRow = (EmpVORowImpl)getEmpVO().createRow();
          tempRow.setAttributeValues(Arrays.asList(tempRow.getAttributeNames()), Arrays.asList(empAttributes));
            empRespList.add(tempRow);
          }
        }
      }
    } catch (SQLException sqlex) {
      throw new Exception("sql exception");
    } catch (Exception ex) {
      throw new Exception("exception");
    } finally {
      try {
        stmt.close();
      } catch (SQLException sqlex) {
        throw new Exception("sql exception");
      }
    }
  }

  return empRespList;
}

Links

I will use this post as a repository of useful links and blogs which I can expect to grow exponentially over the time, so will try to include links on more generalized or important topics of much interest.

– SOA Suite PS6 New Features

Generic:

– SOA SDLC by Mark Nelson

ADF

– Understanding View Accessors

Adapters

-12c JMS Adapter Scalability

Weblogic

Cluster Messaging Protocols

Adapters

– Multiple SOA Suite Revisions with DB Adapter

Mediator

– Message Sequencing Patterns (white paper)

– Parallel Routing Rules

BPEL

BPEL Mania

List of All Instance States

– Transaction Boundaries and Rollbacks

Fault Handling

OTN Article Series

Fault Handling in SOA Suite – Advanced Concepts

Business Rules

Self-Study Course

EDN

EDN Debugging

– Fanning out Events

– SOA 12c – EDN Articles

Continuous Integration

Deploy SOA Composites using Hudson

OSB

Best Practices

– 11g Hands-on Tutorial

– WLST Fundamentals in context of OSB

– Working with Oracle Security Token Service

– One-Way Authentication Policies in OSB

– Coherence Integration

– Caching Strategies for OSB 11g

Out-of-Process Coherence Servers

– 12c Hands-on Tutorial

12c – Series of Articles

– 12c – REST enabling SOA

OWSM

Oracle Blog

BPM

    BPM vs BPEL

     Case Management

Quick Series

Case Activities, Part-I

SOA Governance

 – SOA Governance Through Enterprise Architecture

Fusion Applications

 Fusion Applications Life Cycle

 – Request Flow in Fusion Applications

 – Asynchronous Web Services in Fusion Applications

 – Oracle Fusion DOO – Integrating External Systems using EIL

Customizations

   – Translating Customizations

Transactions when using DB Adapter vs ADF BC Service

Most of us are well aware of global transactions (XA) when using DB Adapter and setting XADataSourceName during creation of DB Connection Pool. ADF BC Services are widely used in Oracle Fusion Applications at Data Service layer  instead DB Adapters. So it’s worth investigating or finding out the scope of transaction when calling these ADF BC Services.

Sample code for this demonstration can be found here and accepts string input, where valid values are ‘DB’ or ‘ADF’.

Conclusion:

  • ADF BC Service call does not get enlisted into main BPEL txn, so system fault, user defined fault or Roll back fault will not revert the changes done by ADF BC Service. So developer should think of compensation in failure scenarios in case of faults.

JDeveloper 11g Issue

Today, i faced an issue while creating the Database Connection for one of the ADF Application. Following is the error that i have got and because of this i did not see the file connections.xml getting created.

java.net.URISyntaxException: Illegal character in path at index 39: file:/C:/DOCUME~1/sivakumar_g01/Local Settings/Temp/credstore-jps-config7177642620278163914.xml]

Over here, i want to reiterate the solution that i found after doing google. The solution is modifying the TEMP environment variable to a path that does not contain spaces. The link discuss on the same.


Pages

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 379 other subscribers

Enter your email address to follow this blog and receive notifications of new posts by email.


%d bloggers like this: