Skip to Content
In this blog I would like to address a very important problem analysis scenario referring a GP callable object implementation of type “WebDynpro GP Interface” that involves JNDI lookup operations to call EJBs (in order to use its business methods).

JNDI lookup operation in Java Web Dynpro components is a very common scenario, where the call to the component is made using a WebDynpro application. This works pretty fine. When the same WebDynpro component implements WebDynpro GP Interface, and is invoked from Guided Procedure runtime instead of a WebDynpro application, it doesn’t work!

Why is this so? Please read on to find an answer 🙂

Scenario

GP process contains a callable object of type “Web Dynpro GP interface”. At runtime, this GP callable object launches the Java WebDynpro component. 

The WD component in turn performs JNDI lookup operations to call EJBs (stateless session bean), to access the required Java Bean methods. The JNDI name is provided for this session bean as recommended. All the required class loader references have been registered in the WD component.

The following figure depicts the usage of WebDynpro Component (with JNDI lookup operations) with (left) and without (right) Guided Procedures.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Environment

SAP NW 04s (NWDS 04s)

SAP Enterprise Portal with GP component

 

Issue 

Code to perform JNDI Lookup operation to call EJB

JNDI name: ERPSelBean                              

                                try {

 

                                                Context l_jndiContext = new InitialContext();

                                               

Object l_obj = l_jndiContext.lookup(“ERPSelBean”);

 

                                                ERPSysssHome l_ERPSys_home =

                                                                (ERPSysssHome) l_obj;

 

                                                ERPSysss l_ERPSys_inst = (ERPSysss) l_ERPSys_home.create();

} catch (RemoteException e) {

                                                // TODO Auto-generated catch block

                                                e.printStackTrace();

 

                                } catch (NamingException e) {

                                                // TODO Auto-generated catch block

                                                e.printStackTrace();

 

                                } catch (CreateException e) {

                                                // TODO Auto-generated catch block

                                                e.printStackTrace();

 

                                } catch (Exception e) {

                                                e.getMessage();

 

                                }

The statement “ERPSysssHome l_ERPSys_home = (ERPSysssHome) l_obj;” returns “ClassCastException”. Type casting to the EJB home interface fails!

This works perfectly fine when the WD component is launched using an application. Using JNDI name in the lookup operation is the standard way of accessing EJBs! I kept on wondering what could be the possible cause of exception, when invoked from GP runtime!  

Issue Analysis

Analyzing this issue wasn’t easy until while debugging I discovered an interesting fact. The following statement returns different object instances for the two runtime scenarios described above.

Object l_obj = l_jndiContext.lookup(“ERPSelBean”);

When executed from GP runtime, JNDI lookup operation returns an object instance of type ObjectReferenceImpl, while it returns the desired EJB proxy object instance (stub) when executed using a WD application.

  

 

Since l_obj contains an unexpected object instance “ObjectReferenceImpl”, the next statement returns a “ClassCastException” !

ERPSysssHome l_ERPSys_home = (ERPSysssHome) l_obj;

Alright I got the cause of the  “ClassCastException”…the next question that came to my mind was “Why did the JNDI lookup operation return “ObjectReferenceImpl” ?

Search made using keyword “ObjectReferenceImpl” helped me find this SAP library link that turned out to be very helpful in implementing the correct solution. It basically describes the possible reasons why the lookup operation returns an unexpected object type.

Here is how the Class loading mechanism in a lookup operation works:

When Client is an application:

  • Application class loader is used to load the looked-up object
  • If it fails, contextClassLoader from the currentThread is used to load the looked-up object
  • If this fails too, com.sap.engine.interfaces.cross.ObjectReference or com.sap.engine.interfaces.cross.UnsatisfiedReference instance is returned

When Client is not an application, only contextClassLoader from the currentThread is used.

It is important to understand that the scenario depicted in this SAP library link applies to the one being described here. The picture below shows the various services involved in the scenario and their relation, and where and why the lookup operation fails when the process is instantiated using Guided Procedure runtime.

Guided Procedures runtime: GP invoking WD Component

  • In this case, contextClassLoader from the currentThread is used to load the classes. When Service A is launched, the thread contains the class loader of this service (which references Service B)
  • Service B in turn looks-up an object bound to Service C, but it fails. The object is not loaded successfully, as the context class loader of the thread does not have a reference of the class loader of Service C.Hence the lookup operation returns an unexpected class type ObjectReference

Web Dynpro Java runtime: WD application invoking WD Component

This scenario works fine as the application class loader has a reference to Service B; hence the lookup operation returns the desired proxy object instance.

 

Solution

It is always said – Keep the solution simple! So it is, as described below:

      ClassLoader l_saveloader =

                                                Thread.currentThread().getContextClassLoader();

                                try {

 

                                                Context l_jndiContext = new InitialContext();

//In Service B source code, before performing the lookup operation reset the value of //contextClassLoader, to reference the class loader of Service B.

                                                Thread.currentThread().setContextClassLoader(

                                                                this.getClass().getClassLoader());

 

Object l_obj = l_jndiContext.lookup(“ERPSelBean”);

 

                                                ERPSysssHome l_ERPSys_home =

                                                                (ERPSysssHome) l_obj;

 

                                                ERPSysss l_ERPSys_inst = (ERPSysss) l_ERPSys_home.create();

} catch (RemoteException e) {

                                                e.printStackTrace();

                                } catch (NamingException e) {

                                                e.printStackTrace();

                                } catch (CreateException e) {

                                                e.printStackTrace();

                                } catch (Exception e) {

                                                e.getMessage();

//Once the looked up object is properly loaded, make sure you set contextClassLoader back to the //original context class loader of Service A.

                                } finally {

                                                Thread.currentThread().setContextClassLoader(l_saveloader);

                                }

I hope this helps my fellow SDN community members in some way or the other!

To report this post you need to login first.

2 Comments

You must be Logged on to comment or reply to a post.

Leave a Reply