In this post I will describe a specific integration use case where we will integrate a Master Items data from Oracle EBS to Salesforce.com using JAVA Web service and PL/SQL APIs.
This will illustrate how we can upload items created/updated in EBS to SFDC by creating Simple JAVA Web service.
Scope:
This is a two-step process where in first step we will write PL/SQL procedure to insert new/updated master item data to oracle staging table and in second step we will write a JAVA web service to upload item data from staging table to SFDC.
This web service will either create new item at SFDC if item does not exists at SFDC or will update item at SFDC if exists.
Implementation:
1. Create Staging table
CREATE TABLE APPS.XX_SFDC_PRODUCTS
(
INVENTORY_ITEM_ID NUMBER,
PRODUCT_CODE VARCHAR2(100 BYTE),
PRODUCT_NAME VARCHAR2(100 BYTE),
DESCRIPTION VARCHAR2(100 BYTE),
PRICE_UOM VARCHAR2(100 BYTE),
PROCESS_STATUS VARCHAR2(100 BYTE),
ERROR_MESSAGE VARCHAR2(100 BYTE),
CREATION_DATE DATE,
CREATED_BY NUMBER,
LAST_UPDATE_DATE DATE,
LAST_UPDATED_BY NUMBER,
REQUEST_ID NUMBER,
PRODUCT_ID VARCHAR2(100 BYTE)
)
2. Create SFDC login table to store SFDC credentials.
CREATE TABLE APPS.XX_SFDC_LOGINS
(
AUTHPOINT VARCHAR2(100 BYTE), --SFDC url from WSDL
USER_NAME VARCHAR2(100 BYTE),
USER_PASSWORD VARCHAR2(100 BYTE),
SECURITY_STRING VARCHAR2(100 BYTE), -- Security Tocken
LOG_FILE VARCHAR2(100 BYTE)
)
3. Create one custom field at SFDC to with the name ‘Oracle_ID__c’ to track oracle inventory item ids at SFDC.
Please follow below link to download WSDL from SFDC.
NOTE- Download WSDL from SFDC after creating Oracle_ID__c custom field
5. Generate client jar from download WSDL.
Please follow below link to generate client jar from WSDL.
This API will stage a master item data into APPS.XX_SFDC_PRODUCTS table.
Package Spec.-
CREATE OR REPLACE PACKAGE APPS.XX_SFDC_IFACE
AS
PROCEDURE insert_products;
END;
/
Package body –
CREATE OR REPLACE PACKAGE BODY APPS.xx_sfdc_iface
AS
PROCEDURE write_log (p_message VARCHAR2)
IS
BEGIN
fnd_file.put_line (fnd_file.LOG, p_message);
END;
PROCEDURE insert_products
IS
l_user_id NUMBER;
l_conc_request_id NUMBER;
BEGIN
write_log ('Starting account insert process ');
l_user_id := fnd_profile.VALUE ('USER_ID');
l_conc_request_id := fnd_profile.VALUE ('CONC_REQUEST_ID');
FOR rec IN
(SELECT msi.inventory_item_id, msi.segment1 product_code,
msi.description product_name,
msi.primary_uom_code price_uom
FROM mtl_system_items_b msi
WHERE 1 = 1
AND msi.organization_id = 204
AND msi.enabled_flag = 'Y'
AND rownum<3 ---add filer here
)
LOOP
write_log ('Inserting ' || rec.product_code);
DBMS_OUtPUT.put_line('Inserting ' || rec.product_code);
INSERT INTO xx_sfdc_products
(inventory_item_id, product_code,
product_name, description, price_uom,
creation_date, created_by, last_update_date,
last_updated_by, request_id
)
VALUES (rec.inventory_item_id, rec.product_code,
rec.product_code, rec.product_name, rec.price_uom,
SYSDATE, l_user_id, SYSDATE,
l_user_id, l_conc_request_id
);
END LOOP;
UPDATE xx_sfdc_products
SET process_status = NULL,
error_message = NULL
WHERE process_status = 'ERROR';
COMMIT;
EXCEPTION
WHEN OTHERS
THEN
write_log ('Exception in insert_products ' || SQLERRM);
DBMS_OUtPUT.put_line('Exception in insert_products ' || SQLERRM);
END;
END;
/
7. Write a JAVA WS to create/update items at SFDC. Below is a code coverage for JAVA WS –
- Establish connection to Oracle as well as SFDC.
- To establish Oracle Connection replace your EBS URL in ods.setURL() statement from getOracleConnection method in below code.
- To establish SFDC connection, insert a row in APPS.XX_SFDC_LOGINS table with below SFDC credentials
AUTHPOINT – SFDC URL to which you are going to connect. You can get this url from your Enterprise WSDL.
USER_NAME – SFDC accounts user name.
USER_PASSWORD – SFDC accounts password
SECURITY_STRING – SFDC security token. Security token comes to mailbox when we reset security token at SFDC side.
LOG_FILE – Log file path.
Web service gets all these credentials from XX_SFDC_LOGINS table and establishes connection to SFDC.
Web service fetches all records with PROCESS_STATUS = ‘NEW’ from staging table and checks whether these records are present at SFDC.
If yes, it updates the product on SFDC otherwise will create new product.
Web service will update process_status , error_message and SFDC product id in staging table.
Please find below WS code.
/*
* OracleSFDCProduct.java
* Verison:1.0 Rishikesh Mule 29/07/2015
*/
package sym.sfdc.product;
import java.net.*;
import java.io.*;
import java.util.*;
import java.sql.*;
import java.text.*;
import oracle.apps.fnd.cp.request.*;
import oracle.apps.fnd.util.*;
import oracle.apps.fnd.common.AppsContext;
import oracle.jdbc.*;
import oracle.jdbc.pool.OracleDataSource;
import com.sforce.soap.enterprise.*;
import com.sforce.soap.enterprise.sobject.*;
import com.sforce.ws.*;
class ProdTab {
String rowid;
String prod_id;
String prod_code;
String prod_name;
String prod_desc;
String prod_invid;
String prod_priceuom;
public ProdTab(String rowid,String prod_id,String prod_code, String prod_name,String prod_desc,String prod_invid,String prod_priceuom ) {
this.rowid=rowid;
this.prod_id=prod_id;
this.prod_code=prod_code;
this.prod_name=prod_name;
this.prod_desc=prod_desc;
this.prod_invid=prod_invid;
this.prod_priceuom=prod_priceuom;
}
public String getRowid() {
return (this.rowid);
}
public String getProd_id() {
return (this.prod_id);
}
public String getProd_code() {
return (this.prod_code);
}
public String getProd_name() {
return (this.prod_name);
}
public String getProd_desc() {
return (this.prod_desc);
}
public String getProd_invid() {
return (this.prod_invid);
}
public String getProd_priceuom() {
return (this.prod_priceuom);
}
}
class PRODWC {
EnterpriseConnection connection=null;
boolean status=false;
String errormsg="";
public LogFile logFile;
public PRODWC() {}
public boolean OpenConn(String authpoint,String uid,String pwd,String token,String logfile) throws Exception {
try {
ConnectorConfig config = new ConnectorConfig();
config.setUsername(uid);
config.setPassword(pwd+token);
config.setAuthEndpoint(authpoint);
if(logfile.length()>0) {
config.setTraceFile(logfile);
config.setTraceMessage(true);
config.setPrettyPrintXml(true);
}
connection = new EnterpriseConnection(config);
status=true;
}
catch (Exception e) {
status=false;
errormsg=e.getMessage();
OracleSFDCProduct pgm1 = new OracleSFDCProduct();
pgm1.logMessage(logFile,"Inside OpenConn "+errormsg);
}
return status;
}
public void CloseConn() throws Exception {
if(connection != null)
connection.logout();
connection = null;
status=false;
}
public String getErrormsg() throws Exception {
return errormsg;
}
public EnterpriseConnection getConnection() throws Exception {
return connection;
}
}
public class OracleSFDCProduct implements JavaConcurrentProgram
{
private String sfauthpoint="";
private String sfusername="";
private String sfpassword="";
private String sftoken="";
private String sflogfile="";
CpContext mCtx;
LogFile logFile;
OutFile outFile;
ReqCompletion lRC; //check != null
Connection mConn = null;
public static void main(String[] args) {
OracleSFDCProduct pgm = new OracleSFDCProduct();
pgm.runProgram(null);
}
public void logMessage(LogFile logFile, String message){
if(logFile!=null)
logFile.writeln(message, LogFile.STATEMENT);
else
System.out.println(message);
}
public void logError(LogFile logFile, String errorMessage){
if(logFile!=null)
logFile.writeln("Error - " + errorMessage, LogFile.ERROR);
else
System.out.println("Error - " + errorMessage);
}
public Connection getOracleConnection(CpContext cpContext, LogFile logFile ){
Connection oracleConnection = null;
if(cpContext==null){
try {
OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:thin:@<ebs_instance_url>:<instance_port>:<instance_SID>");
ods.setUser("apps");
ods.setPassword("apps");
oracleConnection = ods.getConnection();
logMessage(logFile, "Got Connection");
} catch (SQLException ex) {
logMessage(logFile, ex.toString());
}
}else{
oracleConnection = cpContext.getJDBCConnection();
logMessage(logFile, "Able to get Oracle Connection");
}
return oracleConnection;
}
public void runProgram(CpContext pCpContext)
{
Calendar cd=Calendar.getInstance();
SimpleDateFormat df=new SimpleDateFormat("yyyyMMddHHmmss");
SimpleDateFormat ldf=new SimpleDateFormat("dd/MM/yyyy");
String updated_date=ldf.format(cd.getTime());
String errorMessage = null;
boolean errorFlag = false;
mConn = getOracleConnection(pCpContext, logFile);
ReqCompletion lRC = (pCpContext!=null ? pCpContext.getReqCompletion() : null);
logFile = (pCpContext!=null ? pCpContext.getLogFile() : null);
outFile = (pCpContext!=null ? pCpContext.getOutFile() : null);
int request_id = (pCpContext!=null ? pCpContext.getReqDetails().getRequestId() : -1);
int updated_by= (pCpContext!=null ? pCpContext.getReqDetails().getUserInfo().getUserId():-1);
logMessage(logFile,"Selecting credentials");
String lQuery =" select authpoint,user_name,user_password,security_string,log_file from XX_SFDC_LOGINS WHERE rownum = 1";
try
{
PreparedStatement lStmt = mConn.prepareStatement(lQuery);
ResultSet lRs = lStmt.executeQuery();
while( lRs.next() )
{
sfauthpoint = lRs.getString(1);
sfusername = lRs.getString(2);
sfpassword = lRs.getString(3);
sftoken = lRs.getString(4);
logMessage(logFile,"authpoint="+sfauthpoint+" username="+sfusername);
}
lRs.close();
lStmt.close();
}
catch (SQLException e)
{
lRC.setCompletion(ReqCompletion.ERROR, e.toString());
}
try {
sflogfile=sflogfile+"sfdc_outbound_product_"+df.format(cd.getTime())+".log";
sflogfile=sflogfile+"sfdc_inboundorder_"+df.format(cd.getTime())+".log";
logMessage(logFile, "logpath="+sflogfile);
EnterpriseConnection connection=null;
PRODWC sf=new PRODWC();
boolean status=sf.OpenConn(sfauthpoint,sfusername,sfpassword,sftoken,sflogfile);
if(sf.status) {
logMessage(logFile,"Connection Success");
connection=sf.getConnection();
}
else
{
logMessage(logFile,"Connection Failed");
logMessage(logFile,"Failed Msg :"+sf.getErrormsg());
}
logMessage(logFile,"logpath="+sflogfile);
if(status) {
logMessage(logFile,"========================================================");
logMessage(logFile,"Calling procedure start");
PreparedStatement pcstmt = mConn.prepareStatement("begin APPS.XX_SFDC_IFACE.insert_products; end; ");
pcstmt.executeUpdate();
pcstmt.close();
logMessage(logFile,"Calling procedure end");
logMessage(logFile,"====================================================");
Hashtable htdbp=new Hashtable(); // Hashtable for mapping product code with product tab from db
Hashtable htsfp=new Hashtable(); // Hashtable for mapping id with product code from sfdc
Hashtable htsfo=new Hashtable(); // Hashtable for mapping id with Oracle_ID__c from sfdc
int dbpc=0; // Record count from db query.
int sfpc=0; // Record count from sfdc query.
String rowid="";
String prod_id="";
String prod_code="";
String prod_name="";
String prod_desc="";
String prod_invid="";
String prod_priceuom="";
Statement lstmt;
ResultSet rs;
QueryResult result=null;
QueryResult qResult=null;
ProdTab ptab=null;
String pcodes=""; // Comma seperate Products code/Inv.code for checking SFDC
String ppcode=""; // Processing product code
String ppinvid=""; // Processing product inventory id
String soqlQuery=""; // Soql query variable
ArrayList pclist=new ArrayList(); // Product list for Creation
ArrayList pulist=new ArrayList(); // Product list for Updation
int fi,li,batch,rl=0;
List pbel=new ArrayList();
List pbl=new ArrayList();
int strcount=0;
int strindex=0;
String csstr="";
Hashtable hts=null;
StringTokenizer st=null;
SaveResult[] saveResults;
String rstatus="";
String rmsg="";
String uid="";
String rpid="";
int sfdc_process=0;
int sfdc_success=0;
int sfdc_error=0;
logMessage(logFile,"=======================================================");
logMessage(logFile,"Accessing Products from stage table");
lQuery= "SELECT PRODUCT_ID,PRODUCT_CODE,PRODUCT_NAME,DESCRIPTION,INVENTORY_ITEM_ID,PRICE_UOM"+
" ,ROWID ROW_ID"+
" FROM APPS.XX_SFDC_PRODUCTS WHERE PRODUCT_CODE IS NOT NULL " +
" AND NVL(PROCESS_STATUS,'NEW') = 'NEW'";
logMessage(logFile,"Database Query for Product :"+lQuery);
try {
lstmt = mConn.createStatement();
rs = lstmt.executeQuery(lQuery);
while(rs.next() ) {
rowid=rs.getString("ROW_ID");
prod_id=rs.getString("PRODUCT_ID");
prod_code=rs.getString("PRODUCT_CODE");
prod_name=rs.getString("PRODUCT_NAME");
prod_desc=rs.getString("DESCRIPTION");
prod_invid=rs.getString("INVENTORY_ITEM_ID");
prod_priceuom=rs.getString("PRICE_UOM");
if(prod_id==null) prod_id="";
if(prod_code==null) prod_code="";
if(prod_name==null) prod_name="";
if(prod_desc==null) prod_desc="";
if(prod_invid==null) prod_invid="";
if(prod_priceuom==null) prod_priceuom="";
if(pcodes.length()==0)
pcodes="'"+prod_invid+"'";
else
pcodes=pcodes+",'"+prod_invid+"'";
dbpc=dbpc+1;
ptab=new ProdTab(rowid,prod_id,prod_code,prod_name,prod_desc,prod_invid,prod_priceuom);
htdbp.put(prod_invid,ptab);
}
rs.close();
lstmt.close();
}catch(Exception e) {
logMessage(logFile,"Error in database query for Product :"+e.getMessage());
}
logMessage(logFile,"Products count from db : "+htdbp.size());
logMessage(logFile,"==========================================================");
logMessage(logFile,"=======================================================");
logMessage(logFile,"Filter Product codes that exist in SFDC");
if(dbpc>0){
try {
strcount=0;
strindex=0;
csstr="";
hts=new Hashtable();
st=new StringTokenizer(pcodes,",");
while(st.hasMoreElements()) {
if(csstr.length()==0)
csstr=""+(String)st.nextElement();
else
csstr=csstr+","+(String)st.nextElement();
strcount=strcount+1;
if((strcount%150)==0) {
strindex=strindex+1;
hts.put(new Integer(strindex),csstr);
csstr="";
}
}
if((strcount%150)!=0) {
strindex=strindex+1;
hts.put(new Integer(strindex),csstr);
}
for(int hl=1;hl<=hts.size();hl++) {
pcodes=(String)hts.get(new Integer(hl));
soqlQuery = "SELECT Id,Oracle_ID__c FROM Product2 where IsDeleted=false and Oracle_ID__c in ("+pcodes+")";
logMessage(logFile,"SFDC Query for Product : :"+soqlQuery);
qResult = connection.query(soqlQuery);
boolean done = false;
if (qResult.getSize() > 0) {
while (! done) {
SObject[] records = qResult.getRecords();
for ( int i = 0; i < records.length; ++i ) {
Product2 pd = (Product2) records[i];
sfpc=sfpc+1;
htsfp.put(pd.getOracle_ID__c(),pd.getId());
}
if (qResult.isDone()) {
done = true;
} else {
qResult =connection.queryMore(qResult.getQueryLocator());
}
}
}
}
}catch(Exception e) {
logMessage(logFile,"Error in SFDC query for Product :"+e.getMessage());
}
logMessage(logFile,"Products count from SFDC : "+sfpc);
logMessage(logFile,"==========================================================");
logMessage(logFile,"============================================================");
logMessage(logFile,"Creating products list for create and update. ");
try {
Enumeration en=htdbp.keys();
while(en.hasMoreElements()) {
ppcode=(String)en.nextElement();
ProdTab pptab=(ProdTab)htdbp.get(ppcode);
Product2 ppd=new Product2();
if(pptab.getProd_code().length()>0) ppd.setProductCode(pptab.getProd_code());
if(pptab.getProd_name().length()>0) ppd.setName(pptab.getProd_name());
if(pptab.getProd_desc().length()>0) ppd.setDescription(pptab.getProd_desc());
if(pptab.getProd_invid().length()>0) ppd.setOracle_ID__c(pptab.getProd_invid());
if(htsfp.containsKey(ppcode)) {
ppd.setId((String)htsfp.get(ppcode));
pulist.add(ppd);
}
else
{
pclist.add(ppd);
}
}
}catch(Exception e) {
StringWriter errors = new StringWriter();
e.printStackTrace(new PrintWriter(errors));
logMessage(logFile,"Error during product list creation :"+errors.toString());
e.printStackTrace();
logMessage(logFile,"Error during product list creation :"+e.getMessage());
}
logMessage(logFile,"Size of Create Product list :="+pclist.size());
logMessage(logFile,"Size of Update Product list :="+pulist.size());
logMessage(logFile,"===========================================================");
logMessage(logFile,"=============================================================");
logMessage(logFile,"Creating products");
if(pclist.size()>0) {
try {
batch=0;
rl=0;
for(int lp=0;lp<pclist.size();lp=lp+150) {
batch=batch+1;
fi=lp;
li=fi+150;
if(li>pclist.size())
li=pclist.size();
pbel=(List)pclist.subList(fi,li);
Product2[] cpd =new Product2[pbel.size()];
pbel.toArray(cpd);
logMessage(logFile,"Product Creation,Batch="+batch+" Size="+pbel.size());
saveResults = connection.create(cpd);
logMessage(logFile,"size======================="+saveResults.length);
for (int i = 0; i < saveResults.length; i++) {
ProdTab cpptab=(ProdTab)htdbp.get(cpd[i].getOracle_ID__c());
uid=cpptab.getRowid();
if(saveResults[i].isSuccess() ) {
rmsg="";
rstatus="SUCCESS";
rpid=saveResults[i].getId();
logMessage(logFile,"Create Product with Inv. Code,ID,Row ID :"+cpd[i].getOracle_ID__c()+"//"+saveResults[i].getId()+"//"+uid);
sfdc_success=sfdc_success+1;
}
else
{
rmsg=saveResults[i].getErrors()[0].getMessage();
rstatus="ERROR";
rpid="";
logMessage(logFile,"Create Product failed with Code,ID,Row ID :"+cpd[i].getName()+"//"+uid);
sfdc_error=sfdc_error+1;
}
String pcsql="";
if(rstatus.startsWith("SUCCESS")) {
pcsql="update APPS.XX_SFDC_PRODUCTS set PROCESS_STATUS='"+rstatus+"',ERROR_MESSAGE='"+rmsg+"',PRODUCT_ID='"+rpid+"', REQUEST_ID="+request_id+",LAST_UPDATED_BY="+updated_by+",
LAST_UPDATE_DATE = SYSDATE where ROWID='"+uid+"'";
}
else
{
pcsql="update APPS.XX_SFDC_PRODUCTS set PROCESS_STATUS='"+rstatus+"',ERROR_MESSAGE='"+rmsg+"',REQUEST_ID="+request_id+",
LAST_UPDATED_BY="+updated_by+",LAST_UPDATE_DATE=SYSDATE where ROWID='"+uid+"'";
}
logMessage(logFile,"Update DB PRODUCTS CREATE sql :"+pcsql);
PreparedStatement cpstmt = mConn.prepareStatement(pcsql);
cpstmt.executeUpdate();
cpstmt.close();
rl=rl+1;
}
}
} catch(Exception e) {
logMessage(logFile,"Error in Update DB (PRODUCT CREATE) Record :"+e.getMessage());
}
}
logMessage(logFile,"====================================================");
logMessage(logFile,"Updating products");
if(pulist.size()>0) {
try {
batch=0;
rl=0;
for(int lp=0;lp<pulist.size();lp=lp+150) {
batch=batch+1;
fi=lp;
li=fi+150;
if(li>pulist.size())
li=pulist.size();
pbel=(List)pulist.subList(fi,li);
Product2[] upd =new Product2[pbel.size()];
pbel.toArray(upd);
logMessage(logFile,"Product Updation,Batch="+batch+" Size="+pbel.size());
saveResults = connection.update(upd);
for (int i = 0; i < saveResults.length; i++) {
ProdTab upptab=(ProdTab)htdbp.get(upd[i].getOracle_ID__c());
uid=upptab.getRowid();
if(saveResults[i].isSuccess() ) {
rmsg="";
rstatus="SUCCESS";
logMessage(logFile,"Update Product with Code,ID,Row ID :"+upd[i].getOracle_ID__c()+"//"+saveResults[i].getId()+"//"+uid);
sfdc_success=sfdc_success+1;
}
else
{
rmsg=saveResults[i].getErrors()[0].getMessage();
rstatus="ERROR";
logMessage(logFile,"Update Product failed with Code,ID,Row ID :"+upd[i].getName()+"//"+uid);
sfdc_error=sfdc_error+1;
}
String upsql="update APPS.XX_SFDC_PRODUCTS set PROCESS_STATUS='"+rstatus+"',ERROR_MESSAGE='"+rmsg+"',REQUEST_ID="+request_id+",
LAST_UPDATED_BY="+updated_by+",LAST_UPDATE_DATE=SYSDATE where ROWID='"+uid+"'";
logMessage(logFile,"Update DB PRODUCTS UPDATE sql :"+upsql);
PreparedStatement upstmt = mConn.prepareStatement(upsql);
upstmt.executeUpdate();
upstmt.close();
rl=rl+1;
}
}
} catch(Exception e) {
logMessage(logFile,"Error in Update DB (PRODUCT CREATE) Record :"+e.getMessage());
}
}
}
logMessage(logFile,"============================================================");
sfdc_process=dbpc;
logMessage(logFile,"Total Records for Processing : "+sfdc_process);
logMessage(logFile,"Total Records Processed with Success : "+sfdc_success);
logMessage(logFile,"Total Records Processed with Error : "+sfdc_error);
mConn.commit();
sf.CloseConn();
logMessage(logFile,"Closing SFDC Connection");
}
}
catch(Exception e)
{
logMessage(logFile,"Exception " + e.getMessage());
errorFlag = true;
errorMessage = e.getMessage();
}
finally
{
if(pCpContext!=null){
pCpContext.releaseJDBCConnection();
}else{
try {
mConn.close();
} catch (SQLException e) {
logMessage(logFile, "Error while closing DB Connection " + e.getMessage());
}
}
}
if(lRC!=null)
lRC.setCompletion(ReqCompletion.NORMAL, "Request Completed Normal");
}
}
Steps to deploy JAVA web service on $JAVA_TOP
- Copy client jar (Enterprise.jar from step 5) file on $JAVA_TOP
- Extract Enterprise.jar file using below command-
jar xf Enterprise.jar
- Create directory structure sym/sfdc/product on $JAVA_TOP
- Copy JAVA file on sym/sfdc/product directory
- Compile JAVA file on this directory.
Steps to register Java concurrent program-
Define executable
Define Concurrent Program:
Add concurrent program to any responsibility.
Run the program.
Log file will show all the program flow and status about how many items are uploaded on SFDC.
Below are the screenshots from both the environments post running concurrent program.
Oracle EBS Master Item
SFDC product (Uploaded) -
3 comments:
Great explanation ... very nice to see ... keep postings some more ...
r u looking for the jobs on salesforce... ?
do u want to take online training on salesforec...?
do u want job assistance on salesforce?
Salesforce Online Training In Hyderabad
Thank you Rishi.
It was very helpful for me.
Thanks Akshay :)
Post a Comment