Monday, July 22, 2013

Different behaviour of Source or (dot) or (period) operator when passing arguments in Linux and Solaris

The source operator is used for including another file in current script and execute the lines in that file in the current shell context. Therefore the final result is same as that the lines in the sourced file were physically presented in the parent file. I recently found out that the behavior of source operator is different in Linux and Solaris.
If you pass command line arguments to a file you are sourcing inside another shell script, and when you retrieve the passed command line arguments in child (sourced) file,

In Linux,
You will get the parameters you passed as command line parameters when you sourcing the file.

In Solaris,
You will get the command line parameters passed to the parent file as the command line parameters for the child file also.

Therefore if you have a file named test.sh with following lines, (testEcho.sh will echo all the command line arguments passed to it).

. "./testEcho.sh" ted
sh ./testEcho.sh ted


and if you execute it like below,
sh ./test.sh param1 param2 param3


Output in linux,
ted
ted

Output in Solaris,
param1 param2 param3
      ted

Saturday, July 20, 2013

How to get Java system properties and JVM flags of a running Java process - Using jinfo

I wanted to check the current system properties and JVM flags of a Weblogic managed server, so I first used "wlst" (Weblogic scripting tool) to access that managed server. It was a little time consuming task and you need to have a knowledge about the inside of Weblogic server. But later I found out about this jinfo tool. jinfo is a very useful tool for retrieving Java system properties and JVM flags (JVM command line flags)  (and changing values of JVM flags) of a running local Java process or a remote server process. It was lot easier than accessing these properties using "wlst" or "jconsole". According to the "jinfo" documentation, This tool can also be used to get system properties and JVM flags of a remote server process.

But I am going to focus only about how to get those details of a local Java process in a Linux environment.
You can get the process ID of the specific process by doing a command like below in Linux. (Please replace "managed1" with a word (main class name, for example) in the command used for starting the Java process.)

ps -ef | grep "managed1"

In the output of above command, you can get the PID of the relevant Java process.
Then execute the following command. Please replace <PID> with the actual PID of the process.(I am assuming that path to JDK bin folder is in PATH environment variable).

jinfo <PID>

It will attach to the process related to that PID and will show the Java system properties and JVM flags like below.

Attaching to process ID 25965, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 11.0-b17
Java System Properties:

java.vendor = Sun Microsystems Inc.
org.xml.sax.parser = weblogic.xml.jaxp.RegistryParser
sun.java.launcher = SUN_STANDARD
com.sun.xml.ws.api.streaming.XMLStreamReaderFactory.woodstox = true
sun.management.compiler = HotSpot Tiered Compilers
os.name = Linux
sun.boot.class.path = /opt/jdk1.6.0_11/jre/lib/resources.jar:/opt/jdk1.6.0_11/jre/lib/rt.jar...
weblogic.threadpool.MinPoolSize = 50
java.vm.specification.vendor = Sun Microsystems Inc.
.....
VM Flags:

-Dweblogic.Name=managed1 ..................
...................... 
   
Other features of this tool:
(I didn't have a chance to experiment with these yet):
1. Get only JVM flags of the relevant Java process.
jinfo -flags <PID>
2. Get only Java system properties
jinfo -sysprops <PID>
3. Get a value of a specific JVM flag of the relevant Java process.
jinfo -flag <JVM_FLAG_NAME> <PID>
4. Change the value of a specific JVM flag of the relevant Java process.
        a) Enabling  a boolean JVM flag,
         jinfo -flag +<JVM_FLAG_NAME> <PID>
        b) Disabling  a boolean JVM flag,
         jinfo -flag -<JVM_FLAG_NAME> <PID>
        c) Setting a value of a JVM flag
         jinfo -flag  <JVM_FLAG_NAME>=<NEW_VALUE> <PID>

If you get VMVersionMismatchException,

Sometimes you may get following VMVersionMismatchException. 

Attaching to process ID 6461, please wait...
Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at sun.tools.jinfo.JInfo.runTool(JInfo.java:79)
        at sun.tools.jinfo.JInfo.main(JInfo.java:53)
Caused by: sun.jvm.hotspot.runtime.VMVersionMismatchException: Supported versions are 17.1-b03. Target VM is 20.5-b03
        at sun.jvm.hotspot.runtime.VM.checkVMVersion(VM.java:223)
        at sun.jvm.hotspot.runtime.VM.<init>(VM.java:286)
        at sun.jvm.hotspot.runtime.VM.initialize(VM.java:350)
        at sun.jvm.hotspot.bugspot.BugSpotAgent.setupVM(BugSpotAgent.java:594)
        at sun.jvm.hotspot.bugspot.BugSpotAgent.go(BugSpotAgent.java:494)
        at sun.jvm.hotspot.bugspot.BugSpotAgent.attach(BugSpotAgent.java:332)
        at sun.jvm.hotspot.tools.Tool.start(Tool.java:163)
        at sun.jvm.hotspot.tools.JInfo.main(JInfo.java:128)
        ... 6 more

The reason for this is, you are using a "jinfo" tool related to a different java version than the JVM used to start this targeted process. If you get above exception, please find the JDK home of the JVM used for the targeted process, and use the "jinfo" tool in the bin folder of that JDK home.

According to the jinfo tool documentation, it seems this is not a standard tool of the JDK. In the documentation, there is a note saying
"NOTE - This utility is unsupported and may or may not be available in future versions of the JDK. In Windows Systems where dbgent.dll is not present, 'Debugging Tools for Windows' needs to be installed to have these tools working. Also the PATH environment variable should contain the location of jvm.dll used by the target process or the location from which the Crash Dump file was produced.
For example, set PATH=\jre\bin\client;%PATH%
"

How to avoid "java.lang.NoClassDefFoundError: Could not initialize class" when using JFreeChart in a headless server

Recently I encountered following exception when using JFreeChart to generate a graphical chart in a product deployed in a weblogic server.

]] Root cause of ServletException.
java.lang.NoClassDefFoundError: Could not initialize class sun.awt.X11GraphicsEnvironment
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:169)
        at java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(GraphicsEnvironment.java:68)
        at sun.awt.X11.XToolkit.(XToolkit.java:89)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:169)
        at java.awt.Toolkit$2.run(Toolkit.java:834)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.awt.Toolkit.getDefaultToolkit(Toolkit.java:826)
        at sun.swing.SwingUtilities2$AATextInfo.getAATextInfo(SwingUtilities2.java:126)
        at javax.swing.plaf.metal.MetalLookAndFeel.initComponentDefaults(MetalLookAndFeel.java:1556)
        at javax.swing.plaf.basic.BasicLookAndFeel.getDefaults(BasicLookAndFeel.java:130)
        at javax.swing.plaf.metal.MetalLookAndFeel.getDefaults(MetalLookAndFeel.java:1591)
        at javax.swing.UIManager.setLookAndFeel(UIManager.java:541)
        at javax.swing.UIManager.setLookAndFeel(UIManager.java:581)
        at javax.swing.UIManager.initializeDefaultLAF(UIManager.java:1343)
        at javax.swing.UIManager.initialize(UIManager.java:1432)
        at javax.swing.UIManager.maybeInitialize(UIManager.java:1420)
        at javax.swing.UIManager.getDefaults(UIManager.java:660)
        at javax.swing.UIManager.getColor(UIManager.java:702)
        at org.jfree.chart.JFreeChart.(JFreeChart.java:261)
        at org.jfree.chart.ChartFactory.createTimeSeriesChart(ChartFactory.java:1918)
 

 Reason:
During the issue investigation, I found out that the above mentioned Weblogic server is located inside a headless server. (A headless server is a server which does not have a monitor, a key board and a mouse. The control and access to a headless server is done using a network card (remote connection).) It turned out the reason for the above exception is that.

The problem happens because JFreeChart class has some static variables which are initialized using local graphic environment properties retrieved from javax.swing.UIManager.
javax.swing.UIManager in turn tries to get these default properties from local graphic environment.
But because there is no graphic environment in a headless server , initializing sun.awt.X11GraphicsEnvironment class (local graphic environment class) fails and then the loading of JFreeChart class also fails.

Solution:
The solution for this problem is to add -Djava.awt.headless=true to the list of server start arguments of the managed server.  You can change it by,
  1. Login to the Weblogic admin console.
  2. Expand Environment and select Servers.
  3. In the Servers table, click the name of the managed server you want to configure.
  4. Select Configuration > Server Start.
If this is another server or some other java application, you can add this property to wherever place you can specify the JVM arguments for the start of that server or application.



Read more about Java headless mode from: http://www.oracle.com/technetwork/articles/javase/headless-136834.html