/*******************************************************************************
 * Copyright (c) 1998, 2008 Oracle. All rights reserved.
 * This program and the accompanying materials are made available under the 
 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 
 * which accompanies this distribution. 
 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at 
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * Contributors:
 *     Oracle - initial API and implementation from Oracle TopLink
 *     10/20/2008-1.1M4 Michael O'Brien 
 *       - 248748: Add WebLogic 10.3 specific JMX MBean attributes and functions
 *       see <link>http://wiki.eclipse.org/EclipseLink/DesignDocs/248748</link>
 *     11/06/2008-1.1M5 Michael O'Brien 
 *       - 248746: Add getModuleName() implementation and new getApplicationName()
 *     31/03/2009-1.1.1 Michael O'Brien 
 *       - 265369: Cache runtimeServicesMBean until unregistration 
 *       - backport of trunk 3309 27/01/2009 in bug# 256944 (except registration root)
 ******************************************************************************/  
package org.eclipse.persistence.platform.server.wls;

import java.lang.reflect.Method;
import java.security.AccessController;

import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.security.PrivilegedMethodInvoker;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.logging.AbstractSessionLog;
import org.eclipse.persistence.logging.SessionLog;
import org.eclipse.persistence.services.mbean.MBeanDevelopmentServices;
import org.eclipse.persistence.services.weblogic.MBeanWebLogicRuntimeServices;
import org.eclipse.persistence.sessions.DatabaseSession;
import org.eclipse.persistence.sessions.Session;

/**
 * PUBLIC:
 *
 * This is the concrete subclass responsible for representing WebLogic 10 specific behavior.
 * This includes WebLogic 10.3 behavior.
 */
public class WebLogic_10_Platform extends WebLogic_9_Platform {
    // see http://e-docs.bea.com/wls/docs90/jmx/accessWLS.html#1119237
    /** This JNDI address is for JMX MBean registration */
    private static final String JMX_JNDI_RUNTIME_REGISTER = "java:comp/env/jmx/runtime";
    /* 
     * If the cached MBeanServer is not used, then the unregister jndi address must be used to create a context
     * Note: the context must be explicitly closed after use or we may cache the user and get a
     * weblogic.management.NoAccessRuntimeException when trying to use the associated MBeanServer
     * see http://bugs.eclipse.org/238343
     * see http://e-docs.bea.com/wls/docs100/jndi/jndi.html#wp467275  
     */
    /** This JNDI address is for JMX MBean unregistration */    
    private static final String JMX_JNDI_RUNTIME_UNREGISTER = "java:comp/jmx/runtime";
    /** This is the prefix for all MBeans that are registered with their specific session name appended */
    //private static final String JMX_REGISTRATION_PREFIX = "TopLink:Name="; // uncomment for EclipseLink 2.0
    private static final String JMX_REGISTRATION_PREFIX = "org.eclipse.persistence:Name="; // uncomment for EclipseLink 1.1.1
    // Secondary override properties can be set to disable MBean registration
    /** This System property "eclipselink.register.dev.mbean" when set to true will enable registration/unregistration of the DevelopmentServices MBean */
    public static final String JMX_REGISTER_DEV_MBEAN_PROPERTY = "eclipselink.register.dev.mbean";
    /** This System property "eclipselink.register.run.mbean" when set to true will enable registration/unregistration of the RuntimeServices MBean */    
    public static final String JMX_REGISTER_RUN_MBEAN_PROPERTY = "eclipselink.register.run.mbean";
    /** This persistence.xml or sessions.xml property is used to override the moduleName */
    public static final String WEBLOGIC_MODULENAME_PROPERTY = "eclipselink.weblogic.moduleName"; 
    /** This persistence.xml or sessions.xml property is used to override the applicationName */
    public static final String WEBLOGIC_APPLICATIONNAME_PROPERTY = "eclipselink.weblogic.applicationName"; 
    // Any value such as true will turn on the MBean
    protected boolean shouldRegisterDevelopmentBean = System.getProperty(JMX_REGISTER_DEV_MBEAN_PROPERTY) != null;
    protected boolean shouldRegisterRuntimeBean = System.getProperty(JMX_REGISTER_RUN_MBEAN_PROPERTY) != null;

    /**
     * The following constants and attributes are used during reflective API calls
     */
    /** Cache the WebLogic MBeanServer for performance */
    private MBeanServer wlsMBeanServer = null;
    /** Cache the WebLogic ThreadPoolRuntime for performance */    
    private ObjectName wlsThreadPoolRuntime = null;
    /** The JMX context when running as a module */
    private static final String WLS_MODULE_ENV_CONTEXT_LOOKUP = "java:comp/env/jmx/runtime";
    /** The JMX context when running as a non-module */
    private static final String WLS_NON_MODULE_CONTEXT_LOOKUP = "java:comp/jmx/runtime";
    
    private static final String WLS_SERVICE_KEY = "com.bea:Name=RuntimeService,Type=weblogic.management.mbeanservers.runtime.RuntimeServiceMBean";    
    private static final String WLS_SERVER_RUNTIME = "ServerRuntime";    
    private static final String WLS_THREADPOOL_RUNTIME = "ThreadPoolRuntime";
    private static final String WLS_EXECUTE_THREAD_GET_METHOD_NAME = "getExecuteThread";
    // see http://home.bea.com/internal/docs/wiki/p/view/jee/appinfothread
    private static final String WLS_APPLICATION_NAME_GET_METHOD_NAME = "getApplicationName";
    private static final String WLS_MODULE_NAME_GET_METHOD_NAME = "getModuleName";    
    /** Search String in WebLogic ClassLoader for the application:persistence_unit name */
    private static final String WLS_CLASSLOADER_APPLICATION_PU_SEARCH_STRING_PREFIX = "annotation: ";
    
    /** moduleName determination is available during MBean registration only */
    private String moduleName = null;

    /** applicationName determination is available during MBean registration only */
    private String applicationName = null;
    
    /** cache the RuntimeServices MBean */
    private MBeanWebLogicRuntimeServices runtimeServicesMBean = null;    
    /**
     * INTERNAL:
     * Default Constructor: All behavior for the default constructor is inherited
     */
    public WebLogic_10_Platform(DatabaseSession newDatabaseSession) {
        super(newDatabaseSession);
    }

    /**
     * INTERNAL: 
     * serverSpecificRegisterMBean(): Server specific implementation of the
     * creation and deployment of the JMX MBean to provide runtime services for my
     * databaseSession.
     *
     * @return void
     * @see #isRuntimeServicesEnabled()
     * @see #disableRuntimeServices()
     * @see #registerMBean()
     */
    public void serverSpecificRegisterMBean() {
        // get and cache module and application name during registration
        initializeApplicationNameAndModuleName();
        MBeanServer mBeanServerRuntime = null;      
        ObjectName name = null;      
        String sessionName = getMBeanSessionName();
        Context initialContext = null;        
        if (null != sessionName && (shouldRegisterDevelopmentBean || shouldRegisterRuntimeBean)) {
            try {
                initialContext = new InitialContext();
                mBeanServerRuntime = (MBeanServer) initialContext.lookup(JMX_JNDI_RUNTIME_REGISTER);
                // Attempt to register new mBean with the server
                if (shouldRegisterDevelopmentBean) {
                    try {
                        name = new ObjectName(JMX_REGISTRATION_PREFIX + "Development-" + sessionName + ",Type=Configuration");
                    } catch (MalformedObjectNameException mne) {
                        AbstractSessionLog.getLog().log(SessionLog.WARNING, "problem_registering_mbean", mne);
                    } catch (Exception exception) {
                        AbstractSessionLog.getLog().log(SessionLog.WARNING, "problem_registering_mbean", exception);
                    }

                    MBeanDevelopmentServices mbean = new MBeanDevelopmentServices((Session)getDatabaseSession());
                    ObjectInstance info = null;
                    try {
                        info = mBeanServerRuntime.registerMBean(mbean, name);
                    } catch(InstanceAlreadyExistsException iaee) {
                        AbstractSessionLog.getLog().log(SessionLog.WARNING, "problem_registering_mbean", iaee);
                    } catch (MBeanRegistrationException registrationProblem) {
                        AbstractSessionLog.getLog().log(SessionLog.WARNING, "problem_registering_mbean", registrationProblem);
                    } catch (Exception e) {
                        AbstractSessionLog.getLog().log(SessionLog.WARNING, "problem_registering_mbean", e);
                    }
                    AbstractSessionLog.getLog().log(SessionLog.FINEST, "registered_mbean", info);
                }

                if (shouldRegisterRuntimeBean) {
                    try {
                        name = new ObjectName(JMX_REGISTRATION_PREFIX + "Session(" + sessionName + ")");                        
                    } catch (MalformedObjectNameException mne) {
                        AbstractSessionLog.getLog().log(SessionLog.WARNING, "problem_registering_mbean", mne);
                    } catch (Exception exception) {
                        AbstractSessionLog.getLog().log(SessionLog.WARNING, "problem_registering_mbean", exception);
                    }
                    
                    MBeanWebLogicRuntimeServices runtimeServices = new MBeanWebLogicRuntimeServices((AbstractSession)getDatabaseSession());                    
                    ObjectInstance runtimeInstance = null;
                    try {
                        runtimeInstance = mBeanServerRuntime.registerMBean(runtimeServices, name);
                        runtimeServicesMBean = runtimeServices;
                    } catch(InstanceAlreadyExistsException iaee) {
                        AbstractSessionLog.getLog().log(SessionLog.WARNING, "problem_registering_mbean", iaee);
                    } catch (MBeanRegistrationException registrationProblem) {
                        AbstractSessionLog.getLog().log(SessionLog.WARNING, "problem_registering_mbean", registrationProblem);
                    } catch (Exception e) {
                        AbstractSessionLog.getLog().log(SessionLog.WARNING, "problem_registering_mbean", e);
                    }
                    AbstractSessionLog.getLog().log(SessionLog.FINEST, "registered_mbean", runtimeInstance);          
                }
            } catch (NamingException ne) {
                AbstractSessionLog.getLog().log(SessionLog.WARNING, "failed_to_find_mbean_server", ne);
            } catch (Exception exception) {
                AbstractSessionLog.getLog().log(SessionLog.WARNING, "problem_registering_mbean", exception);
            } finally {
                // close the context
                // see http://forums.bea.com/thread.jspa?threadID=600004445
                // see http://e-docs.bea.com/wls/docs81/jndi/jndi.html#471919
                // see http://e-docs.bea.com/wls/docs100/jndi/jndi.html#wp467275
                try {
                    mBeanServerRuntime = null;
                    if(null != initialContext) {
                        initialContext.close();
                    }
                } catch (NamingException ne) {
                    // exceptions on context close will be ignored, the context will be GC'd                   
                }
            }
        }
    }

    /**
     * INTERNAL: 
     * serverSpecificUnregisterMBean(): Server specific implementation of the
     * de-registration of the JMX MBean from its server during session logout.
     *
     * @return void
     * @see #isRuntimeServicesEnabled()
     * @see #disableRuntimeServices()
     */
    public void serverSpecificUnregisterMBean() {
        MBeanServer mBeanServerRuntime = null;      
        ObjectName name = null;      
        String sessionName = getMBeanSessionName();
        Context initialContext = null;        
        if (null != sessionName && (shouldRegisterDevelopmentBean || shouldRegisterRuntimeBean)) {
            try {
                initialContext = new InitialContext();
                mBeanServerRuntime = (MBeanServer) initialContext.lookup(JMX_JNDI_RUNTIME_UNREGISTER);
                // Attempt to register new mBean with the server
                if (shouldRegisterDevelopmentBean) {
                    try {
                        name = new ObjectName(JMX_REGISTRATION_PREFIX + "Development_" + sessionName + ",Type=Configuration");
                    } catch (MalformedObjectNameException mne) {
                        AbstractSessionLog.getLog().log(SessionLog.WARNING, "problem_unregistering_mbean", mne);
                    } catch (Exception exception) {
                        AbstractSessionLog.getLog().log(SessionLog.WARNING, "problem_unregistering_mbean", exception);
                    }

                    AbstractSessionLog.getLog().log(SessionLog.FINEST, "unregistering_mbean", name);
                    try {
                        ((MBeanServer)mBeanServerRuntime).unregisterMBean(name);
                    } catch(InstanceNotFoundException inf) {
                        AbstractSessionLog.getLog().log(SessionLog.WARNING, "problem_unregistering_mbean", inf);
                    } catch (MBeanRegistrationException mbre) {
                        AbstractSessionLog.getLog().log(SessionLog.WARNING, "problem_unregistering_mbean", mbre);                        
                    }                                        
                }

                if (shouldRegisterRuntimeBean) {
                    try {                        
                        name = new ObjectName(JMX_REGISTRATION_PREFIX + "Session(" + sessionName + ")");                        
                    } catch (MalformedObjectNameException mne) {
                        AbstractSessionLog.getLog().log(SessionLog.WARNING, "problem_unregistering_mbean", mne);
                    } catch (Exception exception) {
                        AbstractSessionLog.getLog().log(SessionLog.WARNING, "problem_unregistering_mbean", exception);
                    }

                    AbstractSessionLog.getLog().log(SessionLog.FINEST, "unregistering_mbean", name);
                    try {
                        ((MBeanServer)mBeanServerRuntime).unregisterMBean(name);
                    } catch(InstanceNotFoundException inf) {
                        AbstractSessionLog.getLog().log(SessionLog.WARNING, "problem_unregistering_mbean", inf);
                    } catch (MBeanRegistrationException registrationProblem) {
                        AbstractSessionLog.getLog().log(SessionLog.WARNING, "problem_unregistering_mbean", registrationProblem);
                    }                              
                }
            } catch (NamingException ne) {
                AbstractSessionLog.getLog().log(SessionLog.WARNING, "failed_to_find_mbean_server", ne);
            } catch (Exception exception) {
                // Trap a possible WebLogic specific [weblogic.management.NoAccessRuntimeException]
                AbstractSessionLog.getLog().log(SessionLog.WARNING, "problem_unregistering_mbean", exception);
            } finally {
                // de reference the mbean
                runtimeServicesMBean = null;
                // close the context
                // see http://forums.bea.com/thread.jspa?threadID=600004445
                // see http://e-docs.bea.com/wls/docs81/jndi/jndi.html#471919
                // see http://e-docs.bea.com/wls/docs100/jndi/jndi.html#wp467275
                try {
                    mBeanServerRuntime = null;
                    if(null != initialContext) {
                        initialContext.close();
                    }
                } catch (NamingException ne) {
                    // exceptions on context close will be ignored, the context will be GC'd
                }
            }
        }
    }

    /**
     * INTERNAL: 
     * getModuleName(): Answer the name of the context-root of the application that this session is associated with.
     * Answer "unknown" if there is no module name available.
     * Default behavior is to return "unknown" - we override this behavior here for WebLogic.
     * 
     * There are 4 levels of implementation.
     * 1) use the property override weblogic.moduleName, or
     * 2) perform a reflective weblogic.work.executeThreadRuntime.getModuleName() call (build 10.3+), or
     * 3) extract the moduleName:persistence_unit from the weblogic classloader string representation (build 10.3), or
     * 3) defer to superclass - usually return "unknown"
     *
     * @return String moduleName
     */
    public String getModuleName() {        
        return this.moduleName;
    }
    
    /**
     * INTERNAL: 
     * getApplicationName(): Answer the name of the module (EAR name) that this session is associated with.
     * Answer "unknown" if there is no application name available.
     * Default behavior is to return "unknown" - we override this behavior here for WebLogic.
     * 
     * There are 4 levels of implementation.
     * 1) use the property override weblogic.applicationName, or
     * 2) perform a reflective weblogic.work.executeThreadRuntime.getApplicationName() call (build 10.3+), or
     * 3) extract the moduleName:persistence_unit from the weblogic classloader string representation (build 10.3), or
     * 3) defer to superclass - usually return "unknown"
     *
     * @return String applicationName
     */
    public String getApplicationName() {
        return this.applicationName;
    }
    
    /**
     * INTERNAL:
     * Get the applicationName and moduleName from the runtime WebLogic MBean reflectively
     * @return
     */
    private void initializeApplicationNameAndModuleName() {
        // Get property from persistence.xml or sessions.xml
        String jpaModuleName = (String)getDatabaseSession().getProperty(WEBLOGIC_MODULENAME_PROPERTY);
        String jpaApplicationName = (String)getDatabaseSession().getProperty(WEBLOGIC_APPLICATIONNAME_PROPERTY);      
        
        if (jpaModuleName != null) {
            this.moduleName = jpaModuleName;
        } else {
        	jpaModuleName = getNameFromWeblogic(WLS_MODULE_NAME_GET_METHOD_NAME);
            
            // If we are running a version of WebLogic 10.3 that does not support ExecuteThreadRuntime (from 10.3+) then use the ClassLoader                    
            if(null != jpaModuleName && jpaModuleName.indexOf("@") != -1) {
                this.moduleName = jpaModuleName.substring(jpaModuleName.indexOf("@") + 1);
            } else {
                this.moduleName = jpaModuleName;
            }
        }

        if (jpaApplicationName != null) {
            this.applicationName = jpaApplicationName;
        } else {
        	jpaApplicationName = getNameFromWeblogic(WLS_APPLICATION_NAME_GET_METHOD_NAME);

            // defer to the superclass implementation            
            if(null == jpaApplicationName) {
                 jpaModuleName = super.getApplicationName();
             }
            
            // If we are running a version of WebLogic 10.3 that does not support ExecuteThreadRuntime (from 10.3+) then use the ClassLoader                    
            if(null != jpaApplicationName && jpaApplicationName.indexOf("@") > -1) {
                this.applicationName = jpaApplicationName.substring(jpaApplicationName.indexOf("@") + 1);
            } else {
                this.applicationName = jpaApplicationName;                
            }            
        }
        
        // Final check for null values
        if(null == this.applicationName) {
            this.applicationName = DEFAULT_SERVER_NAME_AND_VERSION;
        }
        if(null == this.moduleName) {
            this.moduleName = DEFAULT_SERVER_NAME_AND_VERSION;
        }
        AbstractSessionLog.getLog().log(SessionLog.FINEST, "mbean_get_application_name", 
                getDatabaseSession().getName(), this.applicationName);
        AbstractSessionLog.getLog().log(SessionLog.FINEST, "mbean_get_module_name", 
                getDatabaseSession().getName(), this.moduleName);
    }

    /**
     * INTERNAL:
     * This method will return the application|module name for WebLogic.
     * If the call to executeThread on the MBean fails - return the current classloader
     * Thread.currentThread().getContextClassLoader() 
     * 
     * ER 248746: Use reflection to obtain the application name (EJB, Web or MDB module)
     * Get either a String containing the module/applicationName or a WebLogic classLoader that contains the module/applicationName in the format...
     * weblogic.utils.classloaders.ChangeAwareClassLoader@19bb43f finder: weblogic.utils.classloaders.CodeGenClassFinder@ab7c2e annotation: org.eclipse.persistence.example.jpa.server.weblogic.enterpriseEAR@enterprise
     * If the getExecuteThread call failed, use the classloader string representation as backup.
     * If the classloader is not in the correct format, defer to superclass.
	 *
     * @return String module|application Name from WLS
     */
    private String getNameFromWeblogic(String getMethodName) {
        Object classLoaderOrString = null;//this.getDatabaseSession().getPlatform().getConversionManager().getLoader();
        Object executeThread = getExecuteThreadFromMBean();
        
        if (executeThread != null) {
            try {
                // perform a reflective public java.lang.String
                // weblogic.work.ExecuteThreadRuntime.<getMethodName>
                Method getMethod = PrivilegedAccessHelper.getPublicMethod(executeThread.getClass(), getMethodName, new Class[] {}, false);
                if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
                    AccessController.doPrivileged(new PrivilegedMethodInvoker(getMethod, executeThread, (Object[]) null));                    
                } else {
                    classLoaderOrString = PrivilegedAccessHelper.invokeMethod(getMethod, executeThread);
                }
                
                if(classLoaderOrString instanceof ClassLoader) {
                    // If we are running a version of WebLogic 10.3 that does not support ExecuteThreadRuntime (from 10.3+) then use the ClassLoader                    
                    String jpaModuleNameRoot = ((ClassLoader)classLoaderOrString).toString();
                    classLoaderOrString = jpaModuleNameRoot.substring(jpaModuleNameRoot.indexOf(
                            WLS_CLASSLOADER_APPLICATION_PU_SEARCH_STRING_PREFIX) + 
                            WLS_CLASSLOADER_APPLICATION_PU_SEARCH_STRING_PREFIX.length());
                }        
            } catch (Exception ex) { // catch all Illegal*Exception and PrivilegedActionException
                /*
                 * If the reflective call to ExecuteThreadRuntime failed for
                 * this an older version of WebLogic 10.3 failed, use the
                 * classloader as a backup method
                 */
                AbstractSessionLog.getLog().log(SessionLog.WARNING,  "problem_with_reflective_weblogic_call_mbean", ex, getMethodName);
            }
        }
        return (String)classLoaderOrString;
    }

    /**
     * INTERNAL:
     * This convenience method will look up a WebLogic execute thread from the runtime 
     * MBean tree.  The execute thread contains application information.  This code 
     * will use the name of the current thread to lookup the corresponding ExecuteThread.
     * The ExecuteThread will allow us to obtain the application name (and version, etc).
     * 
     * Note that the MBeanServer and ThreadPoolRuntime instances will be cached for 
     * performance.
     * 
     * @return application name or null if the name cannot be obtained
     */
    private Object getExecuteThreadFromMBean() {
        // Lazy load the MBeanServer instance
        if (wlsMBeanServer == null) {
            Context initialContext = null;
            try {
                initialContext = new InitialContext();
                try {
                    // The lookup string used depends on the context from which this class is being accessed, i.e. servlet, EJB, etc.
                    // In this case we do not know at runtime whether we are running as a module or not - so we try both lookups
                    // Try java:comp/env lookup  - normally used when the app is a module
                    wlsMBeanServer = (MBeanServer) initialContext.lookup(WLS_MODULE_ENV_CONTEXT_LOOKUP);
                } catch (NamingException e) {
                    // Lookup failed - try java:comp - this is the case when the application is not a module
                    try {
                        wlsMBeanServer = (MBeanServer) initialContext.lookup(WLS_NON_MODULE_CONTEXT_LOOKUP);
                    } catch (NamingException ne) {
                        /*
                         * If the MBeanServer lookup failed, continue and use the classloader as a backup method
                         */
                        AbstractSessionLog.getLog().log(SessionLog.WARNING, "jmx_mbean_runtime_services_mbeanserver_lookup_failed", ne);
                    }
                }
                
                
            } catch (NamingException nex) {
                AbstractSessionLog.getLog().log(SessionLog.WARNING, "problem_unregistering_mbean", nex);
            } finally {
                // close the context
                try {
                    if(null != initialContext) {
                        initialContext.close();
                    }
                } catch (NamingException ne) {
                    // exceptions on context close will be ignored, the context will be garbage collected
                }
            }
        }
        // Now that we know that the MBeanServer has been initialized - we use it
        // Initialize the threadPoolRuntime and get the executeThreadRuntime
        //this.getDatabaseSession().getPlatform().getConversionManager().getLoader();
        if (wlsMBeanServer != null) {
            // Lazy load the ThreadPoolRuntime instance
            if (wlsThreadPoolRuntime == null) {
                try {
                    ObjectName service = new ObjectName(WLS_SERVICE_KEY);
                    ObjectName serverRuntime = (ObjectName) wlsMBeanServer.getAttribute(service, WLS_SERVER_RUNTIME);
                    wlsThreadPoolRuntime = (ObjectName) wlsMBeanServer.getAttribute(serverRuntime, WLS_THREADPOOL_RUNTIME);
                } catch (Exception ex) {
                    AbstractSessionLog.getLog().log(SessionLog.WARNING, "jmx_mbean_runtime_services_threadpool_initialize_failed", ex);                                        
                }
            }
            // Get the executeThreadRuntimeObject
            if (wlsThreadPoolRuntime != null) {
                try {
                    // Perform a reflective getExecuteThread()
                    return wlsMBeanServer.invoke(wlsThreadPoolRuntime, 
                            WLS_EXECUTE_THREAD_GET_METHOD_NAME, 
                            new Object[] { Thread.currentThread().getName() }, new String[] { String.class.getName() });
                } catch (Exception ex) {
                    /*
                     * If the reflective call to get the executeThreadRuntime object failed on the MBean because
                     * this an older version of WebLogic 10.3, continue and use the classloader as a backup method
                     */
                    AbstractSessionLog.getLog().log(SessionLog.WARNING,
                            "jmx_mbean_runtime_services_get_executethreadruntime_object_failed", ex);
                }
            }
        }
        return null;
    }
    
    /**
     * Remove JMX reserved characters from the session name
     * @param aSession
     * @return
     */
    private String getMBeanSessionName() {
        // Check for a valid session - should never occur though        
        if(null != getDatabaseSession() && null != getDatabaseSession().getName()) {
            // remove any JMX reserved characters when the session name is file:/drive:/directory
            return getDatabaseSession().getName().replaceAll("[=,:]", "_");
        } else {
            AbstractSessionLog.getLog().log(SessionLog.WARNING, "session_key_for_mbean_name_is_null");
            return null;
        }
    }
    
}
