Saturday, January 10, 2015

Multi-threaded Java Concurrent program in Oracle eBusiness Suite R12

The customer had an existing custom PL/SQL concurrent program that looped through a result set and processed each row sequentially. As volume grew, this sequential processing took longer and longer as some rows that took longer to process held up the remaining rows in the result set.
We needed something to process rows in parallel, 5 or 10 at a time. Using DBMS_PARALLEL_EXECUTE in PL/SQL did not yield good results, so we had to look for something else.
A Google search on "Java Multithreading" got me to this wonderful post  that provided the direction for us to create a Java concurrent program to enable parallel processing.

The Java concurrent program uses the Executor framework - java.util.concurrent.* - as well as the Inner Class pattern so that the threads can access members of the executor as if they are part of the outer executor class.

public class MyParallelConcProg implements JavaConcurrentProgram {

    public class WorkerThread implements Runnable {



Logic:
//1. Define number of parallel threads
String numberOfThreads = parameters.get("p_number_of_threads");
        numberOfThreads = (numberOfThreads == null) ? "5" : numberOfThreads;

//2. Create the parallel thread pool
        ExecutorService executor = Executors.newFixedThreadPool(new Integer(numberOfThreads)); // parameter then profile

//3. Call PL/SQL function that returns a REF CURSOR for the result set to loop through
String sql = "begin ? := MYPKG.get_cursor;end;" ;
               
 try {
          stmt = cpContext.getJDBCConnection().prepareCall(sql); // cpContext.getJDBCConnection().prepareStatement(sql);
          i = 1;
          stmt.registerOutParameter(i++, OracleTypes.CURSOR);

           stmt.execute();

          resultSet = ((OracleCallableStatement)stmt).getCursor(1); 

//4. Now loop through the result set and process each row
while (resultSet.next()
{
              Runnable worker = new MyParallelConcProg .WorkerThread( ....
  
             executor.execute(worker);
}


//5. The run() method in the WorkerThread class processes the row from the result set
    public void run() {
            String prefix = Thread.currentThread().getName() + " " + <some identifier from the result set>+ ": ";
        // get connection from the pool
            OracleConnection connection = (OracleConnection)cpContext.getExtraJDBCConnection(this, cpContext.getSessionId());
        OracleCallableStatement stmt = null;
stmt = (OracleCallableStatement)connection.prepareCall(
                " BEGIN MYPKG.process_row(...); end;" 
        

Each thread uses a separate database connection, so there are always n+1 DB connections while the concurrent program runs. While it is tempting to use a large number of threads, there is a practical limit and we have not seen the need to go over 5 threads for our requirement. We did go as high as 20 threads during stress testing and were very satisfied with the results. 

The DB connections for each thread do not inherit the concurrent request settings such as Request Id, Requestor etc. However, since the WorkerThread is an Inner Class, it has access to the cpcontext member of the outer executor class and can get to the concurrent request id by calling cpContext.getReqDetails().getRequestId())

I have skipped details like parameters passed to the PL/SQL statements since your requirements will be different. Also details pertaining to concurrent program log messages can be found in the developer's guide, so I have not mentioned that in this post.



Thursday, January 8, 2015

Descriptive Flexfields in Oracle Application Express

It has been over 2 years since I posted anything on this blog. I have had the good fortune of being on a project where I have been exposed to a variety of technologies - Oracle Fusion Middleware, SOA Suite, Exalogic, Exadata, Oracle DBFS, Oracle Application Express - to name a few.

In this post, I invite you to check out the Oracle APEX application where I have implemented Oracle eBusiness Suite like Descriptive Flexfield functionality.

The solution uses only PL/SQL and APEX - no AJAX or JavaScript.

You can access the application here. Log in using "guest/ myflex_demo".

If you like what you see and would like more information, add a comment with your email address and I will gladly share my code.

Tuesday, January 1, 2013

Happy 2013! A new year , a new blog post - BIP Images, OA_MEDIA and the desktop

Happy New Year! Wow, another eventful year gone by , yet there's so much to do, so much more to learn!

Embedding images within BI Publisher templates is old hat now and very well documented - this blog post is specific to using BIP within eBusiness Suite and accessing images dynamically using $OA_MEDIA (or any other environment variable).

The Oracle XML Publisher Report Designer's Guide has a section on using OA_MEDIA reference to load images dynmically from the application server using the following syntax:

url:{concat('${OA_MEDIA}','/',IMAGE_FILE)}

However the documentation does not mention how to use this reference when previewing the template from the BIP desktop plugin for MS Word. When I asked some developers what they did to preview their images I found that most of them either did not preview images on the desktop or if they did, they would change the Alternative text (Alt-text) region of the dummy image in the RTF template!

A simple configuration allows you to use the OA_MEDIA reference on the desktop to preview your images and to use the same template on all platforms.

XDO.cfg setup to reference $OA_MEDIA on BIP desktop

1.       Copy the LOGO images to a directory on your desktop – say C:\XDO\Images
2.       Look for “xdo example.cfg” under “C:\Program Files (x86)\Oracle\BI Publisher\BI Publisher Desktop\Template Builder for Word\config” or “"C:\Program Files\Oracle\XML Publisher Desktop\Template Builder for Word\config” depending on the BIP desktop version you have installed.
3.       Copy “xdo example.cfg” to “xdo.cfg”
4.       Modify xdo.cfg -(a) Look for system-temp-dir and give it a valid directory name
e.g. <property name="system-temp-dir">c:\temp</property>
(b) Look for </properties>
(c) Add a line above that
<property name="user-variable.OA_MEDIA">file:///C:\XDO\images</property>
Note: The directory name MUST match the location of your images on the desktop
5.       Save xdo.cfg


With this configuration, you have set $OA_MEDIA to C:\XDO\images on your desktop. You can now preview logos in BIP desktop before loading the RTF template into eBusiness Suite.

Tuesday, May 1, 2012

Collaborate 12 Keynote Address by Captain Mark Kelly

Captain Mark Kelly, US Navy captain, astronaut, Commander of Space Shuttle Endeavor's final mission, husband of Congresswoman Gabrielle Giffords delivered the keynote address at Collaborate 12 in Las Vegas on Monday April 23rd, 2012. The address was titled "Leadership, Teamwork, Courage". Simple. 

Captain Kelly is a marvelous orator and knows how to tell a story. He shared his experiences and the lessons he learned along the way and all I could think was "RESPECT Captain!"

Some of the things I came away with after the address - 

1) What you are at the beginning does not define what you become in the end. Hard work and determination play a large part in molding your future.

2) None of us is as dumb as all of us. When decisions are made by a team, it is very rare to hear voices of dissent for several reasons, mainly fear of rejection. So team members choose to remain silent and quite often it results in the wrong decision being made. How many times have you seen the junior most team member being asked for an opinion before a senior member? Something worth considering...

3) There is nothing so important that should prevent you from communicating with your team. Clear and timely communication prevents a lot of issues down the road.

4) There is nothing stronger than the human spirit, as Captain Kelly's wife has shown. You can deny the acceptance of failure. Perseverance, patience and strong will can move mountains.

Thank you Captain Kelly!

Thursday, February 23, 2012

Listagg - or in my case Listagg AAAAARGH!

Oracle 11gR2 introduces a new analytical and reporting function LISTAGG that orders data within each group based on the ORDER BY clause and then concatenates the values of the measure column. See Chapter 22 in the Oracle Data Warehousing Guide 11g Release 2. 


Why Listagg AAAAARGH!? If I had taken the time 2 weeks ago to familiarize myself with the new features in 11gR2, I wouldn't have written a function to do exactly what LISTAGG does! 



Friday, February 10, 2012

A blast from the (not so distant) past!

Some time last week I got an email from someone who'd googled "extensible attributes" and stumbled upon my presentation at Collaborate '08. It's nice to know that he found this useful. 
I haven't dealt with TCA Extensible attributes since late 2007. 


Here's the link to the presentation - http://cdmsig.oaug.org/file/Collab08SIGTCAEXT1209951946.pdf

Friday, February 3, 2012

Ubuntu - I am because we are

I just installed Ubuntu 10.04 on my 7 year old Dell Inspiron 6000 that was running Windows XP and had become virtually unusable. I am kicking myself for not having gone the Ubuntu route earlier because I am extremely impressed with the ease of installation, setup and running. I feel like a kid with a new toy - one that I "built" myself and the best thing is that it's free!

I now have a LAMP environment - Linux Apache MySQL PHP - that I can play with.

Next - loading some Oracle software !


Wednesday, January 25, 2012

When developers have too much time on their hands..


I can attest to that, it's not microwave safe. Pierce with a spoon and you should be good to go.


Never tried that.



Thursday, January 5, 2012

Happy 2012!

So another year has passed and another one begun! More resolutions made going in through one year and out the other! 
Every year I make a list of things I'd like to get done but this year I'm going to stick to just a few.


- Keep learning
- Keep sharing
- Experiment
- Read a lot
- Enjoy life!


Hope 2012 is a happy and prosperous year!

Sunday, December 25, 2011

Wednesday, December 21, 2011

Sortable Excel Output - Rows to Columns using RTF templates in BI Publisher

I had a math professor who said stuff like "The problem is always tough until you find the solution", which makes sense, if you don't think about it. 


I was tasked with solving what seemed like a tough problem. An existing BIP report used this XML structure to generate MS Excel output using an RTF template.


G_MAIN
  G_CUSTOMER
    CUSTOMER
    TOTAL_SALES
    G_PRODUCTS
       G_PRODUCT
           PCT_TOTAL
           SALES_AMT


The output from a BIP report needed to be changed so that it went from this


Customer
Total $

Breakdown by Product



Product
% of Total
Sales $
Cust1
100,000.00
Prod1
25.00%
25,000.00


Prod2
30.00%
30,000.00


Prod4
45.00%
45,000.00
Cust2
200,000.00
Prod2
40.00%
80,000.00


Prod3
25.00%
50,000.00


Prod5
35.00%
70,000.00
Cust3
1,000,000.00
Prod1
30.00%
300,000.00


Prod3
40.00%
400,000.00


Prod4
15.00%
150,000.00


Prod5
15.00%
150,000.00
Cust4
2,000,000.00
Prod1
20.00%
400,000.00


Prod2
20.00%
400,000.00


Prod3
20.00%
400,000.00


Prod4
20.00%
400,000.00


Prod5
20.00%
400,000.00








to this

Customer
Total $
Prod1

Prod2

Prod3

Prod4

Prod5



% of Total
Sales $
% of Total
Sales $
% of Total
Sales $
% of Total
Sales $
% of Total
Sales $
Cust1
100,000.00
25.00%
25000
30.00%
30000
0.00%
0
45.00%
45000
0.00%
0
Cust2
200,000.00
0.00%
0
40.00%
80000
25.00%
50000
0.00%
0
35.00%
70000
Cust3
1,000,000.00
30.00%
300000
0.00%
0
40.00%
400000
15.00%
150000
15.00%
150000
Cust4
2,000,000.00
20.00%
400000
20.00%
400000
20.00%
400000
20.00%
400000
20.00%
400000



Getting the XML data to include all products, even ones that the customer did not purchase, was easy - good old data densification. In addition, an independent group of all products was required to display product names in the labels. Effectively, the XML structure changed (a little) to



G_MAIN
 G_ALLPRODUCTS
  G_CUSTOMER
    CUSTOMER
    TOTAL_SALES
    G_PRODUCTS
       G_PRODUCT
           PCT_TOTAL
           SALES_AMT



To get the XML rows to appear as columns wasn't too bad either. All that was needed was a <?for-each@cell:grpname?> directive and the BIP engine takes care of the rest.


 The RTF template looks like this:


Customer #
 Total $
F PRODUCT
end
F % of Total
Sales $
end
FECust1
9,999.99
F
0.00%
99.99
end  E


where F = <?for-each@cell:grpname?> , end = <?end for-each-group?> 
FE = <?for-each:groupname?>, E =  <?end for-each?>