Oracle APPS Java Application with Shell Concurrent Program
Hello,
In my previous tutorial, I did an example about Java Concurrent Program with External Jars. In this tutorial, I will develop a simple java application which generates an Excel(xlsx) file and run it as a shell concurrent program in Oracle EBS.
First of all, we need to understand the differences between java concurrent program and shel concurrent program for custom java applications.
Java Concurrent Program | Java Application With Shell Concurrent Program |
---|---|
JDBC is not required | JDBC is required and must be manually configured |
APPS Context is already initialized | APPS Context should be manually initialized |
Logging is not a problem | Logging is a problem |
Hard to configure | Easy to configure |
Database credentials are hidden | Database credentials must be open |
1.Since JDBC connection will be manually configured, the correct version of driver must be identified. In order to do this, check database version with following sql script.
1 2 3 |
select * from v$version |
2. Download jdbc driver by clicking to following link
3. Since java application will generate excel files, we need to download apache-poi API. Click to the following link
http://poi.apache.org/download.html
4. Open Netbeans and select “New Project” from menu.
5. Choose Java Application and click to Next.
6. Define project name and main class.
7. Create a java class for jdbc connection.
8. Define class name and package.
9. Open project properties by right clicking to the project.
10. Move on to the “Libaries” section. We need to add POI and jdbc jars into project classpath. Therefore click to the “Add Jar/Folder” button.
11. Add all of the poi jars and ojdb6.jar file.
12. Create one more class for excel operations.
13. Define class name and package.
14. XXConnection: This class has two methods which return Connection and Oracle Connection. At line 21, Update connection string and credentials for your database.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package src.xx; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import oracle.jdbc.OracleConnection; /** * * @author Anil */ public class XXConnection { private String conString = "jdbc:oracle:thin:@<host_name>:<port>:<sid>"; private String userName = "apps"; private String password = "apps"; public Connection getConnection() { try { Class.forName("oracle.jdbc.driver.OracleDriver"); } catch (ClassNotFoundException ex) { System.out.println(ex.getMessage()); return null; } Connection connection = null; System.out.println("Trying connection for:"+conString+", "+userName+", "+password); try { connection = DriverManager.getConnection(conString, userName, password); } catch (SQLException e) { System.out.println(e.getMessage()); } if (connection != null) { System.out.println("Connected to database!"); } else { System.out.println("Failed to make connection!"); } return connection; } public OracleConnection getOracleConnection() { try { Class.forName("oracle.jdbc.driver.OracleDriver"); } catch (ClassNotFoundException ex) { System.out.println(ex.getMessage()); return null; } OracleConnection connection = null; System.out.println("Trying connection for:"+conString+", "+userName+", "+password); try { connection = (OracleConnection) DriverManager.getConnection(conString, userName, password); } catch (SQLException e) { System.out.println(e.getMessage()); } if (connection != null) { System.out.println("Connected to database!"); } else { System.out.println("Failed to make connection!"); } return connection; } } |
14. Test the connection in main method.
1 2 3 4 5 6 7 |
public static void main(String[] args) { // TODO code application logic here XXConnection c = new XXConnection(); OracleConnection con = c.getOracleConnection(); } |
Result:
1 2 3 4 5 6 |
run: Trying connection for:jdbc:oracle:thin:@<host_name>:<port>:<sid>, apps, apps Connected to database! BUILD SUCCESSFUL (total time: 1 second) |
15.After excel file is generated, it will be better to keep some information about transaction, request and file. To do that we need to create a database table with following script
1 2 3 4 5 6 7 |
create table hr.xx_excel_sh_result ( request_id number, file_name varchar2(100), path_file_name varchar2(300) ); |
16. ExcelOperations: Excel file is generated in this class. createExcel method takes sql query, file name, sheet name as parameters. Excel rows and columns are generated dynamically depending on sql query. Pay attention to disposing poi workbook in finally block. Since poi creates temporary xml files in /tmp folder, there is a possibility that there may not be free spaces anymore. This may cause EBS not working properly.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package src.xx; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.logging.Level; import java.util.logging.Logger; import oracle.jdbc.OracleConnection; import oracle.jdbc.OraclePreparedStatement; import oracle.jdbc.OracleResultSet; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFCellStyle; import org.apache.poi.xssf.usermodel.XSSFDataFormat; import org.apache.poi.xssf.usermodel.XSSFFont; /** * * @author Anil */ public class ExcelOperations { public final static String OA_HTML = System.getenv("OA_HTML"); public void createExcel (String sql, String fileName, String sheetName, String requestId) { FileOutputStream out = null; SXSSFWorkbook wb = null; XXConnection c = new XXConnection(); OracleConnection con = c.getOracleConnection(); OraclePreparedStatement ps = null; OracleResultSet rs= null; String fullFilePath = null; int rowCount = 1; if (OA_HTML != null) { fullFilePath = OA_HTML + "/" + fileName + ".xlsx"; } else { fullFilePath = fileName+".xlsx"; } try { out = new FileOutputStream(fullFilePath); //create workbook. //the rowAccessWindowSize parameter in constructor specifies that at what row count poi flushes the ram //if rows are flushed, there won't be any access to those rows. //Therefore, rowAccessWindowSize parameter may be high in some applications where you need to access previously created rows. However, this may cause some performance problems. //In this tutorial, 1 will be sufficient. Use -1 for unlimited access. wb = new SXSSFWorkbook(1); //In order to keep date as formatted, we need to create Cell Style object and confiure it. XSSFCellStyle dateStyle = (XSSFCellStyle) wb.createCellStyle(); XSSFDataFormat dateFormat = (XSSFDataFormat) wb.createDataFormat(); dateStyle.setDataFormat(dateFormat.getFormat("[$-809]dd.mm.yyyy;@")); Sheet sh = wb.createSheet(sheetName); ps = (OraclePreparedStatement) con.prepareStatement(sql); rs = (OracleResultSet) ps.executeQuery(); ResultSetMetaData metaData = ps.getMetaData(); Row headerRow = sh.createRow(0); setHeaderRow(headerRow, metaData, wb); while (rs.next()) { Row row = sh.createRow(rowCount); int colCount = 1; while (metaData.getColumnCount() != colCount - 1) { Cell cell = row.createCell(colCount-1); String colType = metaData.getColumnTypeName(colCount); String colName = metaData.getColumnLabel(colCount); if ("VARCHAR2".equals(colType)) { cell.setCellValue(rs.getString(colName)); } else if ("NUMBER".equals(colType)) { cell.setCellValue(rs.getDouble(colName)); } else if ("DATE".equals(colType)) { if (rs.getDate(colName) != null) { cell.setCellValue(rs.getDate(colName)); cell.setCellStyle(dateStyle); } } else { System.out.println("Bilinmeyen verip tipi!"); } colCount++; } rowCount++; } wb.write(out); out.close(); wb.dispose(); insertResult(fileName, fullFilePath, Integer.parseInt(requestId)); } catch (SQLException ex) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); } catch (FileNotFoundException ex) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); } catch (IOException ex) { Logger.getLogger(ExcelOperations.class.getName()).log(Level.SEVERE, null, ex); } finally { try { if (ps != null) { ps.close(); } if (rs != null) { rs.close(); } if (wb != null) { wb.dispose(); } if (out != null) { out.close(); } if (con != null) { con.close(); } } catch (SQLException ex) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); } catch (IOException ex) { Logger.getLogger(ExcelOperations.class.getName()).log(Level.SEVERE, null, ex); } } } private void setHeaderRow(Row headerRow, ResultSetMetaData metaData, SXSSFWorkbook wb) throws SQLException { int colCount = metaData.getColumnCount(); XSSFFont font = (XSSFFont) wb.createFont(); font.setBold(true); XSSFCellStyle style = (XSSFCellStyle) wb.createCellStyle(); style.setFont(font); for (int i = 1; i <= colCount; i++) { Cell headerCell = headerRow.createCell(i-1); headerCell.setCellValue(metaData.getColumnLabel(i)); headerCell.setCellStyle(style); } } private void insertResult(String fileName, String pathFileName, int requestId) { XXConnection c = new XXConnection(); Connection con = c.getConnection(); String sql = "INSERT into hr.xx_excel_sh_result (request_id, file_name, path_file_name) values (?, ?, ?)"; PreparedStatement ps = null; try { ps = con.prepareStatement(sql); ps.setInt(1, requestId); ps.setString(2, fileName); ps.setString(3, pathFileName); ps.execute(); } catch (SQLException ex) { Logger.getLogger(ExcelOperations.class.getName()).log(Level.SEVERE, null, ex); } finally { try { if (ps != null) { ps.close(); } if (con != null) { con.close(); } } catch (SQLException ex) { Logger.getLogger(ExcelOperations.class.getName()).log(Level.SEVERE, null, ex); } } } } |
17. Do the following changes in Main class. Please pay attention that application will get parameters from main method arguments which will be sent by Shell Script.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package src.xx; /** * * @author Anil */ public class Main { /** * @param args the command line arguments */ public static void main(String[] args) { // TODO code application logic here //arg[0] = SQL Script //arg[1] = File Name //arg[2] = Sheet Name //arg[3] = REQUEST_ID ExcelOperations excel = new ExcelOperations(); excel.createExcel(args[0], args[1], args[2], args[3]); } } |
18. Clean and Build the application and upload it into application server $PER_TOP/bin via FTP. Pay attention to uploading net beans project folder (with every other files inside it).
19. Write a shell script which has “.prog” extension. Pay attention to first four parameters are provided by concurrent program. These are:
$0: The shell script to be executed
$1: Oracle user/password
$2: Applications user_id
$3: Application user_name
$4: Concurrent program request_id
$5 and after $5 parameters are the parameters that defined in concurrent program.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#!/bin/sh echo 'Printing parameters....' echo '0:'$0 echo '1:'$1 echo '2:'$2 echo '3:'$3 echo '4:'$4 echo '5:'$5 echo '6:'$6 echo '7:'$7 java -jar /u01/data_appl/apps/apps_st/appl/per/12.0.0/bin/XXJavaExcelShApp/dist/XXJavaExcelShApp.jar "$5" "$6" "$7" "$4" MYSTATUS=`sqlplus -s $1 <<! SET HEADING FEEDBACK OFF PAGESIZE 0 declare l_result boolean; l_session_id number; begin fnd_global.INITIALIZE(l_session_id, null, null, null,null, -1, null, null, null, null, $4, null,null,null,null,null,null,-1); l_result := fnd_concurrent.set_completion_status('WARNING','Review log file for details.'); commit; end; / exit; !` echo 'FCPLOGIN:'$FCP_LOGIN echo 'Finished printing parameters.' |
20. Upload “prog” file into $PER_TOP/bin. We need to link the shell script. In order to this, execute the following unix command. If this operation is successful, a file with same name must be created in same path.
1 2 3 |
ln -s $FND_TOP/bin/fndcpesr /u01/data_appl/apps/apps_st/appl/per/12.0.0/bin/XxAnilShProg |
21. Give neccessary authorization to the file with CHMOD command.
22. At this point, file structure should be look like:
23. Define executable file:
24. Define concurrent program:
25. Run the program and test it;
Not: If program ends with error like “File not found”, upload prog file via FTP by using BINARY mode.
26. Result:
1 2 3 |
select * from hr.xx_excel_sh_result where request_id = 5858410; |
Source: http:/http://oracleappsnotes.wordpress.com/2012/02/21/all-about-host-concurrent-programs/
very nice post. One question. How do you open the output in excel when you click on the concurrent job output view button. The file you create is not linked to the concurrent job output is it?
Hello Justin,
Unfortunately, we cannot link it to concurrent output. You can make an OAF page for submitting concurrent request.
You can also insert file into a BLOB column and display it on same OAF page.
Thanks Kuntan, I was able to do that. I am directly using a Java Concurrent Program, without any shell wrapper. After you are done creating the file do
setOutFile(filePathandName);
this will redirect the OUTFILE_NAME in the FND_CONC_REQUEST
When you click on the View Ouput button it will try to open the file. Unfortunately at this time Oracle will stream the file and open everything in EXCEL as binary, so you see all the junk characters.
The way to overcome that is to stream the file in Binary, so I had to really dig through the whole view output process. Found one table FND_FILE_TEMP, this is the table where you can set how do you want the set TRANSFER=’BINARY’. This essentially says to Oracle what you are getting is Binary.
After you set the transfer mode here, the Excel opens with properly formatted columns and sheets.
Thanks a bunch, hope it helps others as well.
Hello Justin,
This is a valuable information. Thank you for contribution.
Best Regards
It’s worth noting in your comparing and contrasting Shell Concurrent Programs/Java Concurrent Programs, that the classpath configuration for Java Concurrent Programs cannot contain environment variables such as $JAVA_TOP.
This means Shell Concurrent Programs are more suitable to generalized deployments, where $JAVA_TOP may have different directory paths.
I want to access UNIX server to fetch a file inside from JCP.. How is it possible?