Saturday, June 25, 2011

WebLogic Server JMS WLST Script – Who is Connected To My Server

This blog was originally posted on http://blogs.oracle.com/jamesbayer when I worked for Oracle.

Update 6/27/2011: Tom Barnes indicated a clarification, check out the comments.
Ever want to know who was connected to your WebLogic Server instance for troubleshooting?  JT_Switchboard_770x540An email exchange about this topic and JMS came up this week, and I’ve heard it come up once or twice before too.  Sometimes it’s interesting or helpful to know the list of JMS clients (IP Addresses, JMS Destinations, message counts) that are connected to a particular JMS server.  This can be helpful for troubleshooting.  Tom Barnes from the WebLogic Server JMS team provided some helpful advice:
The JMS connection runtime mbean has “getHostAddress”, which returns the host address of the connecting client JVM as a string. 
A connection runtime can contain session runtimes, which in turn can contain consumer runtimes.  The consumer runtime, in turn has a “getDestinationName” and “getMemberDestinationName”.  I think that this means you could write a WLST script, for example, to dump all consumers, their destinations, plus their parent session’s parent connection’s host addresses.   
Note that the client runtime mbeans (connection, session, and consumer) won’t necessarily be hosted on the same JVM as a destination that’s in the same cluster (client messages route from their connection host to their ultimate destination in the same cluster).

Writing the Script

So armed with this information, I decided to take the challenge and see if I could write a WLST script to do this.  It’s always helpful to have the WebLogic Server MBean Reference handy for activities like this.  This one is focused on JMS Consumers and I only took a subset of the information available, but it could be modified easily to do Producers.  I haven’t tried this on a more complex environment, but it works in my simple sandbox case, so it should give you the general idea.
# Better to use Secure Config File approach for login as shown here http://buttso.blogspot.com/2011/02/using-secure-config-files-with-weblogic.html
connect('weblogic','welcome1','t3://localhost:7001')
 
# Navigate to the Server Runtime and get the Server Name
serverRuntime()
serverName = cmo.getName()
 
# Multiple JMS Servers could be hosted by a single WLS server
cd('JMSRuntime/' + serverName + '.jms' )
jmsServers=cmo.getJMSServers()
 
# Find the list of all JMSServers for this server
namesOfJMSServers = ''
for jmsServer in jmsServers:
 namesOfJMSServers = jmsServer.getName() + ' '
 
# Count the number of connections
jmsConnections=cmo.getConnections()
print str(len(jmsConnections)) + ' JMS Connections found for ' + serverName + ' with JMSServers ' + namesOfJMSServers
 
# Recurse the MBean tree for each connection and pull out some information about consumers
for jmsConnection in jmsConnections:
 try:
  print 'JMS Connection:'
  print '  Host Address = ' + jmsConnection.getHostAddress()
  print '  ClientID = ' + str( jmsConnection.getClientID() )
  print '  Sessions Current = ' + str( jmsConnection.getSessionsCurrentCount() )
  jmsSessions = jmsConnection.getSessions()
  for jmsSession in jmsSessions:
   jmsConsumers = jmsSession.getConsumers()
   for jmsConsumer in jmsConsumers:
    print '   Consumer:'
    print '     Name = ' + jmsConsumer.getName()
    print '     Messages Received = ' + str(jmsConsumer.getMessagesReceivedCount())
    print '     Member Destination Name = ' + jmsConsumer.getMemberDestinationName()
 except:
  print 'Error retrieving JMS Consumer Information'
  dumpStack()
 
# Cleanup
disconnect()
exit()

Example Output

I expect the output to look something like this and loop through all the connections, this is just the first one:
1 JMS Connections found for AdminServer with JMSServers myJMSServer
JMS Connection:
  Host Address = 127.0.0.1
  ClientID = None
  Sessions Current = 16
   Consumer:
     Name = consumer40
     Messages Received = 1
     Member Destination Name = myJMSModule!myQueue

Notice that it has the IP Address of the client.  There are 16 Sessions open because I’m using an MDB, which defaults to 16 connections, so this matches what I expect.  Let’s see what the full output actually looks like:
D:\Oracle\fmw11gr1ps3\user_projects\domains\offline_domain>java weblogic.WLST d:\temp\jms.py
 
Initializing WebLogic Scripting Tool (WLST) ...
 
Welcome to WebLogic Server Administration Scripting Shell
 
Type help() for help on available commands
 
Connecting to t3://localhost:7001 with userid weblogic ...
Successfully connected to Admin Server 'AdminServer' that belongs to domain 'offline_domain'.
 
Warning: An insecure protocol was used to connect to the
server. To ensure on-the-wire security, the SSL port or
Admin port should be used instead.
 
Location changed to serverRuntime tree. This is a read-only tree with ServerRuntimeMBean as the root.
For more help, use help(serverRuntime)
 
1 JMS Connections found for AdminServer with JMSServers myJMSServer
JMS Connection:
  Host Address = 127.0.0.1
  ClientID = None
  Sessions Current = 16
   Consumer:
     Name = consumer40
     Messages Received = 2
     Member Destination Name = myJMSModule!myQueue
   Consumer:
     Name = consumer34
     Messages Received = 2
     Member Destination Name = myJMSModule!myQueue
   Consumer:
     Name = consumer37
     Messages Received = 2
     Member Destination Name = myJMSModule!myQueue
   Consumer:
     Name = consumer16
     Messages Received = 2
     Member Destination Name = myJMSModule!myQueue
   Consumer:
     Name = consumer46
     Messages Received = 2
     Member Destination Name = myJMSModule!myQueue
   Consumer:
     Name = consumer49
     Messages Received = 2
     Member Destination Name = myJMSModule!myQueue
   Consumer:
     Name = consumer43
     Messages Received = 1
     Member Destination Name = myJMSModule!myQueue
   Consumer:
     Name = consumer55
     Messages Received = 1
     Member Destination Name = myJMSModule!myQueue
   Consumer:
     Name = consumer25
     Messages Received = 1
     Member Destination Name = myJMSModule!myQueue
   Consumer:
     Name = consumer22
     Messages Received = 1
     Member Destination Name = myJMSModule!myQueue
   Consumer:
     Name = consumer19
     Messages Received = 1
     Member Destination Name = myJMSModule!myQueue
   Consumer:
     Name = consumer52
     Messages Received = 1
     Member Destination Name = myJMSModule!myQueue
   Consumer:
     Name = consumer31
     Messages Received = 1
     Member Destination Name = myJMSModule!myQueue
   Consumer:
     Name = consumer58
     Messages Received = 1
     Member Destination Name = myJMSModule!myQueue
   Consumer:
     Name = consumer28
     Messages Received = 1
     Member Destination Name = myJMSModule!myQueue
   Consumer:
     Name = consumer61
     Messages Received = 1
     Member Destination Name = myJMSModule!myQueue
Disconnected from weblogic server: AdminServer
 
 
Exiting WebLogic Scripting Tool.
Thanks to Tom Barnes for the hints and the inspiration to write this up.
Image of telephone switchboard courtesy of http://www.JoeTourist.net/ JoeTourist InfoSystems

Friday, June 17, 2011

WebLogic Server–Use the Execution Context ID in Applications–Lessons From Hansel and Gretel

This blog was originally posted on http://blogs.oracle.com/jamesbayer when I worked for Oracle.

I learned a neat trick this week.  Don’t let your breadcrumbs go to waste like Hansel and Gretel did!  Keep track of the code path, logs and errors for each request as they flow through the system.  hansel-uns-gretelEarlier this week an OTN forum post in the WLS – General category by Oracle Ace John Stegeman asked a question how to retrieve the Execution Context ID so that it could be used on an error page that a user could provide to a help desk or use to check with application administrators so they could look up what went wrong.  What is the Execution Context ID (ECID)?  Fusion Middleware injects an ECID as a request enters the system and it says with the request as it flows from Oracle HTTP Server to Oracle Web Cache to multiple WebLogic Servers to the Oracle Database. It’s a way to uniquely identify a request across tiers.  According to the documentation it’s:

The value of the ECID is a unique identifier that can be used to correlate individual events as being part of the same request execution flow. For example, events that are identified as being related to a particular request typically have the same ECID value.  The format of the ECID string itself is determined by an internal mechanism that is subject to change; therefore, you should not have or place any dependencies on that format.

The novel idea that I see John had was to extend this concept beyond the diagnostic information that is captured by Fusion Middleware.  Why not also use this identifier in your logs and errors so you can correlate even more information together!  Your logging might already identify the user, so why not identify the request so you filter down even more.  All you need to do inside of WebLogic Server to get ahold of this information is invoke DiagnosticConextHelper:

weblogic.diagnostics.context.DiagnosticContextHelper.getContextId()

This class has other helpful methods to see other values tracked by the diagnostics framework too.  This way I can see even more detail and get information across tiers.

In performance profiling, this can be very handy to track down where time is being spent in code.  I’ve blogged and made videos about this before.  JRockit Flight Recorder can use the WLDF Diagnostic Volume in WLS 10.3.3+ to automatically capture and correlate lots of helpful information for each request without installing any special agents and with the out-of-the-box JRockit and WLS settings!  You can see here how information is displayed in JRockit Flight Recorder about a single request as it calls a Servlet, which calls an EJB, which gets a DB connection, which starts a transaction, etc.  You can get timings around everything and even see the SQL that is used.

ecid

http://download.oracle.com/docs/cd/E21764_01/web.1111/e13714/using_flightrecorder.htm#WLDFC480

Recent versions of the WLS console also are able to visualize this data too, so it works with other JVMs besides JRockit when you turn on WLDF instrumentation.

I wrote a little sample application that verified to myself that the ECID did actually cross JVM boundaries.  I invoked a Servlet in one JVM, which acted as an EJB client to Stateless Session Bean running in another JVM.  Each call returned the same ECID.  You need to turn on WLDF Instrumentation for this to work otherwise the framework returns null.  I’m glad John put me on to this API as I have some interesting ideas on how to correlate some information together.

ecidScreenshot

Monday, June 6, 2011

Sharing a Class With a WebLogic Classloader Without Modifying Scripts

This blog was originally posted on http://blogs.oracle.com/jamesbayer when I worked for Oracle.

classloaderA question (mostly original with some slight editing on my part) came up on our internal mailing list today that I thought might be interesting to those that have cloassloader questions.  For a quick refresher on the options for classloading in WebLogic, click the image to see a larger image or get the presentation from the bottom of the post on slideshare.  The key for this scenario is the DOMAIN_HOME/lib directory.

Scenario: We have a embeddable java component which gets shipped within every webapp in our suite of products. This embeddable java component has a cache object which is loaded every time the component is initialized by the webapp. This cache object is a singleton and has the same content across all the webapps. We have one managed server in which many ear files are deployed to. Each ear initialize's this embeddable java component on start up.

Issue: When I profile the objects loaded (using Classloader Analysis Tool) in each of these web apps I see that this cache singleton object is loaded in each one of the web app class loaders. I would like to load just one of these singleton objects and reference the same object across all the ear's. This saves heap space and all the calls that it takes to create this cache object in each ear. Even though its a singleton I see that since the class loaders are different for each ear that it creates a new cache object. I have an understanding of the weblogic class loader hierarchies (bootstrap, system, webapp etc). I don't want to move this embeddable java component and its dependencies to the system class loader by modifying the scripts or environment variables.  Are there other options?

My answer:  Have a look at the DOMAIN_HOME/lib directory.

http://download.oracle.com/docs/cd/E21764_01/web.1111/e13706/classloading.htm#i1096881

To try it, just drop the jars you want to be shared in the DOMAIN_HOME/lib directory.

Here’s an example.



      
 
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package test;
 
import java.util.Map;
 
/**
*
* @author jbayer
*/
public class SharedCache 
{
   public static final Map<String,String> mapCache = new java.util.HashMap<String, String> ();
    
    static    
    {
        System.out.println( SharedCache.class.toString() + " loaded into a classloader" + SharedCache.class.getClassLoader().toString() );
    }
 
    public SharedCache() 
    {
    }
    
}

Now I use this class in two webapps named WebApplication1 and WebApplication2 that refer to the SharedCache class in their identical index.jsp

<%@page contentType="text/html" pageEncoding="UTF-8" import="test.*"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        <h1>Hello World! Cache size: 
            
<% 
    SharedCache myCache = new SharedCache();
    out.print( myCache.mapCache.size() );                    
%>
        
        </h1>
    </body>
</html>

When the test.SharedCache class is loaded from each web application respectively, you should see the following in the System.out showing that 2 versions of the class were loaded into separate classloaders for each web module:

class test.SharedCache loaded into a classloaderweblogic.utils.classloaders.ChangeAwareClassLoader@bde4ac finder: weblogic.utils.classloaders.CodeGenClassFinder@1ff9980 annotation: WebApplication1@web
class test.SharedCache loaded into a classloaderweblogic.utils.classloaders.ChangeAwareClassLoader@4a4acd finder: weblogic.utils.classloaders.CodeGenClassFinder@3f08e3 annotation: WebApplication2@web

Once you drop the jar with the test.SharedCache in the DOMAIN_HOME/lib and restart the server, and access both web apps, you'll see the class is now shared from one system classloader:

class test.SharedCache loaded into a classloaderjava.net.URLClassLoader@88e2dd

And if you use CAT, you can see that both applications use the same System Classloader.  Click to enlarge.  The hash code shows that the same classloader is used for both applications.

catSharedCache

Check out Jeff West’s recording on WebLogic Server classloaders and CAT.

http://www.slideshare.net/jeffreyawest/weblogic-filtering-classloader-and-classloader-analysis-tool-demo