Oracle Apps Java Concurrent Program With External Jars
Hi,
In Oracle EBS, majority of concurrent programs that we defined are pl/sql programs or reports. However, in order to meet some complex requirements, we need other types of concurrent programs such as java concurrent program or shell concurrent program.
These kind of requirements may be;
- Implementation of SFTP.
- Web Service Clients with JAX-WS.
- Generating XLSX outputs.
- Generating PDF outputs.
- Complex business logic
In this article, I will cover the following topics;
- Defining Java Concurrent Program With External jars.
- JAX-WS Web Service Client in Oracle APPS.
Before moving on tutorial, implementing a java concurrent program requires much more effort and focus than pl/sql concurrent programs.
P.S: In this tutorial, I will be using Netbeans because of the JAX-WS support. As far as i know, JAX-WS Web Service clients cannot be generated by JDeveloper which comes with E-Business Suite patches. Using Netbeans for implementing java concurrent program requires just one more additional step comparing to JDeveloper.
1. During tutorial, in order to keep all of the externals organized, create a directory named “libs” in the operating system.
2. Connect to the E-Business Suite application server with a FTP Client and get “common”, “cp”, “util” folders which are located in $JAVA_TOP/oracle/apps/fnd to the “libs” folder that we created in first step. Pay attention to the exact same folder paths between “libs” and $JAVA_TOP.
3. Connect to the E-Business Suite application server with a SSH client and find out which JAVA version is used with the following commands.
1 2 3 4 5 6 7 |
[appldemo@demo classes]$ java -version java version "1.6.0_10" Java(TM) SE Runtime Environment (build 1.6.0_10-b33) Java HotSpot(TM) Server VM (build 11.0-b15, mixed mode) [appldemo@demo classes]$ |
4. Download JDK and install it to your development environment.
5. Open Netbeans 7.4 and create a New Java Application Project.
6. Un-check Main Class and give a proper project name which should start with “XX”.
7. Create a new JAVA file and give proper name and package which should also start with “XX”.
8. Left click on your project and open Project Properties. Move to the Libraries on left menu.Click to the “Add Jar/Folder” button.
9. Choose libs folder which we created in step 1.
10. Open the JAVA file which is created in seventh step. Implement JavaConcurrentProgram interface for your java class.
11. Overwrite interface methods.
12. Delete throw statements.
1 2 3 4 5 |
@Override public void runProgram(CpContext cc) { } |
The CpContext parameter provides many context information about Concurrent Program. You can gen DB connection with following command.
1 2 3 |
cc.getJDBCConnection() |
In addition, apps context (user_id, resp_id, resp_appl_id) may be get from CpContext object.
13. In order to generate Web Service Client in Netbeans, related plugins need to be installed. Do the followings for installing plugin unless you have already installed.
14. Create a new “Java Class Libary” project on netbeans. This will be the web service client jar that we will be using in our concurrent program.
15. Give proper name to your project.
16. Change the Java Platform of your projects to the JDK which you have already installed on fourth step. This step is very important in order to prevent “Unsupported major minor version” error on E-Business Suite application server.
17. Create a new web service client on new project.
18. At this point, we need an example web service. Following calculator WSDL is used in this tutorial. In order to download WSDL, click to following link:
http://soatest.parasoft.com/calculator.wsdl
19. Choose the WSDL file from your local environment. Give proper name to your package and click Finish. Netbeans will parse WSDL and generate stubs and methods that you will use in order to consume web service.
20. Create a new JAVA Class.
21. Change necessary information for you class.
21. Move “add”, “divide”, “multiply”, “subtract” web service function to your class from Web Service References -> calculator -> Calculator -> ICalculator.
22. Generate public getters and setters for your methods.
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 |
/* * 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 xx.calculator; /** * * @author Anil */ public class XXCalculator { public float callAdd(float x, float y) { return add(x, y); } public float callDivide(float x, float y) { return divide(x, y); } public float callMultiply(float x, float y) { return multiply(x, y); } public float callSubtract(float x, float y) { return subtract(x, y); } private static float add(float x, float y) { xx.calculator.Calculator service = new xx.calculator.Calculator(); xx.calculator.ICalculator port = service.getICalculator(); return port.add(x, y); } private static float divide(float numerator, float denominator) { xx.calculator.Calculator service = new xx.calculator.Calculator(); xx.calculator.ICalculator port = service.getICalculator(); return port.divide(numerator, denominator); } private static float multiply(float x, float y) { xx.calculator.Calculator service = new xx.calculator.Calculator(); xx.calculator.ICalculator port = service.getICalculator(); return port.multiply(x, y); } private static float subtract(float x, float y) { xx.calculator.Calculator service = new xx.calculator.Calculator(); xx.calculator.ICalculator port = service.getICalculator(); return port.subtract(x, y); } } |
23. Clean and Build your project. This will generate jar file under dist folder in Netbeans.
24. Copy jar file to the “libs” folder that we created in first step.
25. Open the java concurrent program project properties.
26. Move to the Libraries and Click Add Jar Folder button.
27. Choose the jar file which is created at 25 step under “libs” folder.
28. Change your java concurrent program class. Pay attention to the line 68 where we call web service client jar. Clean and Build project.
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 |
/* * 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 xxntc.javaconcrpg; import oracle.apps.fnd.cp.request.CpContext; import oracle.apps.fnd.cp.request.JavaConcurrentProgram; import oracle.apps.fnd.cp.request.LogFile; import oracle.apps.fnd.cp.request.OutFile; import oracle.apps.fnd.cp.request.ReqCompletion; import oracle.apps.fnd.util.NameValueType; import oracle.apps.fnd.util.ParameterList; import xx.calculator.XXCalculator; /** * * @author Anil */ public class XXAnilWsClient implements JavaConcurrentProgram { OutFile output; LogFile logFile; @Override public void runProgram(CpContext cc) { //initialize output and log output = cc.getOutFile(); logFile = cc.getLogFile(); boolean hasError = false; boolean divideByZero = false; float pNum1 = 0; float pNum2 = 0; float addResult = 0; float divideResult = 0; float multiplyResult = 0; float subtractResult = 0; //get the parameters from concurrent ParameterList params = cc.getParameterList(); while (params.hasMoreElements()) { NameValueType ntv = params.nextParameter(); if ("P_SAYI1".equals(ntv.getName())) { pNum1 = Float.parseFloat(ntv.getValue()); output.writeln(ntv.getName() + ":" + ntv.getValue()); } else if ("P_SAYI2".equals(ntv.getName())) { pNum2 = Float.parseFloat(ntv.getValue()); output.writeln(ntv.getName() + ":" + ntv.getValue()); } else { logFile.writeln("Unexpected Parameter!", LogFile.ERROR); hasError = true; break; } } if (hasError) { cc.getReqCompletion().setCompletion(ReqCompletion.ERROR, "Error"); } else { // jar file that we created and added to projet XXCalculator calc = new XXCalculator(); addResult = calc.callAdd(pNum1, pNum2); if (pNum2 == 0) { logFile.writeln("Second parameter is zero. Division operation will be skipped.", LogFile.EXCEPTION); divideByZero = true; cc.getReqCompletion().setCompletion(ReqCompletion.WARNING, "Uyari"); } else { divideResult = calc.callDivide(pNum1, pNum2); } multiplyResult = calc.callMultiply(pNum1, pNum2); subtractResult = calc.callSubtract(pNum1, pNum2); output.writeln(pNum1 + " + " + pNum2 + " = " + addResult); output.writeln(pNum1 + " / " + pNum2 + " = " + divideResult); output.writeln(pNum1 + " * " + pNum2 + " = " + multiplyResult); output.writeln(pNum1 + " - " + pNum2 + " = " + subtractResult); if (!divideByZero) { cc.getReqCompletion().setCompletion(ReqCompletion.NORMAL, "Ok"); } } } } |
29. Upload your concurrent program java file to the application server $JAVA_TOP. Create a new custom folder in $JAVA_TOP. Upload your web service client jar to custom folder. Use the following command in order to compile your concurrent program java file. Please pay attention to -cp option in order to prevent NoClassDef error. -d option will create your .class file with the package that you specify in java file.
1 2 3 |
javac -cp .:xxntc/externallibs/* -d $JAVA_TOP XXAnilWsClient.java |
30. Create concurrent program executable as following. Pay attention to Executable File Name and Package which must be same as your java file and package.
31. Creating Concurrent program is the most important step because all external jar files must be specified with JAVA_TOP, appsborg in OPTIONS field.
Pay attention to followings.
- JAVA_TOP path -> /u01/data_appl/apps/apps_st/comn/java/classes
- appsborg.zip location -> /u01/data_appl/apps/apps_st/comn/java/lib/appsborg.zip
- Your external jar files -> /u01/data_appl/apps/apps_st/comn/java/classes/xxntc/externallibs/*
Combine above steps in one -classpath statement and write it to the OPTIONS field in concurrent program.
-classpath /u01/data_appl/apps/apps_st/comn/java/classes:/u01/data_appl/apps/apps_st/comn/java/lib/appsborg.zip:/u01/data_appl/apps/apps_st/comn/java/classes/xxntc/externallibs/*
32. Define your program parameters.
33. Add program to request group.
34. Switch to the request group responsibility and run the program with test parameters.
Test the results:
Regards 🙂
congratulations! perfectoo
This paragraph will assist the internet viewers for building up new blog or even a weblog from start to end.
Which one?
Great blog,
the external jars are unable to find by java concurrent program while executing.
please help.
Hello Ravi,
Thank you. Which ebs version are you using?
Hi
12.1.3 version
I am placing up to 13 jars for my program at $JAVA_TOP/xx/jars/*
Then my path like below:
-classpath java_top path:appsberg.zip path:jars path
While running java concurrent program it was not finding classes which i imported from jars.
java.lang.NoClassDefFoundError: org/springframework/context/ApplicationContext
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:169)
at oracle.apps.fnd.cp.request.Run.main(Run.java:152)
Caused by: java.lang.ClassNotFoundException: org.springframework.context.ApplicationContext
at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
Ravi,
Sorry for late reply, I was on vocation. I never tried to use spring jars with EBS but It should work if you define classpath option correct during concurrent program definition. Did you make it work?
Thank you for your help.
We are using not only spring jars other jars also. Observed classpath option allowing 250 characters only.
I given classpath option as below:
-classpath java_top path:appsberg.zip path:jars path i.e. $JAVA_TOP/xx/jars/*
I am doing the following now:
1. If i extract jars getting .class files libraries, so i made all .class files libraries together into xxlibs.zip .
2. I copied xxlibs.zip folder to the location which is same as appsberg.zip location.
3. Now the classpath option as follows:
-classpath java_top path:appsberg.zip path:xxlibs.zip path
If i am doing above 3 steps my java concurrent program working fine, where as if i keep jars in xxlibs.zip instead of .class file library, java concurrent program was not finding classes which i imported from jars.
If we observe inside appsberg.zip, we don’t have jars and all are .class file libraries.
Is the above approach is fine ?
Can you please provide a way to me to use jars ?
Ravi,
If you made it work, I don’t see anything wrong with your approach. I am going to try same requirement when I have time.
Thank you so much for posting such a great blog and please post your observations after trying the same requirement.
Have Anyone tried this in 12.2.4? We have the same requirement with 10 to 12 external Jars. Also in 12.2.4 appsborg.zip is no longer available. Looks like this is replaced with “ebsAppsborgManifest.jar”
When I tried giving the path to above “ebsAppsborgManifestr.jar” in OPTIONS along with path to my external jars. The concurrent program not able to load seeded classes for ex., jadbc drivers etc..
SO question is how can we specify “OPTIONS” value with external jars in 12.2.4
I have same requirement. did you get any solution for 12.2.4?
Thanks
Hi all,
A better solution would be using shell concurrent program. Ask your admin to install jdk8+ in your application server. Write web service client with jaxws-maven-plugin + spring boot. Write a prog file which runs executable jar file with dynamic concurrent parameters.
HI,
Thank you very much for this post…Your the only one person posted with full clear and step by step process and very much understandable..
I have tried the same steps, but it is failing while running the java concurrent program and getting error like
java.lang.NoClassDefFoundError: oracle/adf/mds/metamodel/MMFactory
at oracle.apps.fnd.cp.request.Run.main(Run.java:126)..
if i add class path in options field, that is recognizing remaining jars…I am trying to add the custom jars to existing class path in the system….could you please suggest any other suggestion regarding above issue….