Monday, February 14, 2011

Interesting, but unsolved error when building Apache Axiom

These days I was busy with getting the WSO2 Carbon trunk building successfully. While working on it, I encountered an interesting build failure when building Apache Axiom with tests.

Lets think, the Carbon trunk's structure is as follows.


If I go to the Axiom folder and build it with tests, it builds successfully. But, if I stay in Dir1 (i.e. the parent directory which Axiom is in) and give the maven command to build all modules in Dir1 (with tests), I get this error. This seems to happen when building the Axiom OSGI Test Suite.

The current artifact axiom-osgi-run-1.2.12-SNAPSHOT.jar is not a valid bundle
Running org.apache.axiom.test.ServiceTest
Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 0 sec
[FATAL ERROR] org.apache.felix.ipojo.junit4osgi.plugin.Junit4osgiPlugin#execute() caused a linkage error (java.lang.LinkageError) and may be out-of-date. Check the realms:
[FATAL ERROR] Plugin realm = app0.child-container[org.apache.felix:maven-junit4osgi-plugin:1.0.0]
urls[0] = file:/home/amila/.m2/repository/org/apache/felix/maven-junit4osgi-plugin/1.0.0/maven-junit4osgi-plugin-1.0.0.jar
urls[1] = file:/home/amila/.m2/repository/junit/junit/3.8.1/junit-3.8.1.jar
urls[2] = file:/home/amila/.m2/repository/org/apache/felix/org.apache.felix.framework/1.6.1/org.apache.felix.framework-1.6.1.jar
urls[3] = file:/home/amila/.m2/repository/org/apache/felix/org.osgi.core/1.2.0/org.osgi.core-1.2.0.jar
urls[4] = file:/home/amila/.m2/repository/org/apache/felix/org.osgi.compendium/1.2.0/org.osgi.compendium-1.2.0.jar
urls[5] = file:/home/amila/.m2/repository/org/apache/felix/
urls[6] = file:/home/amila/.m2/repository/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.jar
urls[7] = file:/home/amila/.m2/repository/org/apache/felix/org.apache.felix.ipojo/1.2.0/org.apache.felix.ipojo-1.2.0.jar
urls[8] = file:/home/amila/.m2/repository/org/apache/felix/org.apache.felix.ipojo.metadata/1.2.0/org.apache.felix.ipojo.metadata-1.2.0.jar
urls[9] = file:/home/amila/.m2/repository/org/apache/felix/org.apache.felix.ipojo.handler.extender/1.2.0/org.apache.felix.ipojo.handler.extender-1.2.0.jar
urls[10] = file:/home/amila/.m2/repository/org/apache/felix/org.apache.felix.ipojo.junit4osgi/1.0.0/org.apache.felix.ipojo.junit4osgi-1.0.0.jar
urls[11] = file:/home/amila/.m2/repository/net/sourceforge/cobertura/cobertura/1.9/cobertura-1.9.jar
urls[12] = file:/home/amila/.m2/repository/oro/oro/2.0.8/oro-2.0.8.jar
urls[13] = file:/home/amila/.m2/repository/asm/asm/2.2.1/asm-2.2.1.jar
urls[14] = file:/home/amila/.m2/repository/asm/asm-tree/2.2.1/asm-tree-2.2.1.jar
urls[15] = file:/home/amila/.m2/repository/log4j/log4j/1.2.9/log4j-1.2.9.jar
urls[16] = file:/home/amila/.m2/repository/org/apache/ant/ant/1.7.0/ant-1.7.0.jar
urls[17] = file:/home/amila/.m2/repository/org/apache/ant/ant-launcher/1.7.0/ant-launcher-1.7.0.jar
urls[18] = http://felix.extensions:9/
[FATAL ERROR] Container realm = plexus.core
urls[0] = file:/media/dev/software/apache-maven-2.1.0/lib/maven-2.1.0-uber.jar
urls[1] = file:/home/amila/.m2/repository/org/apache/maven/archetype/archetype-packaging/2.0-alpha-4/archetype-packaging-2.0-alpha-4.jar
urls[2] = file:/home/amila/.m2/repository/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.jar
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] loader constraint violation: loader (instance of org/codehaus/classworlds/RealmClassLoader) previously initiated loading for a different type with name "org/codehaus/plexus/util/xml/XMLWriter"
[INFO] ------------------------------------------------------------------------
[INFO] Trace
java.lang.LinkageError: loader constraint violation: loader (instance of org/codehaus/classworlds/RealmClassLoader) previously initiated loading for a different type with name "org/codehaus/plexus/util/xml/XMLWriter"
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(
at java.lang.ClassLoader.defineClass(
at Method)
at java.lang.ClassLoader.loadClass(
at org.codehaus.classworlds.RealmClassLoader.loadClassDirect(
at org.codehaus.classworlds.DefaultClassRealm.loadClass(
at org.codehaus.classworlds.RealmClassLoader.loadClass(
at java.lang.ClassLoader.loadClass(
at org.apache.felix.ipojo.junit4osgi.plugin.XMLReport.generateReport(
at org.apache.felix.ipojo.junit4osgi.plugin.Junit4osgiPlugin.executeTest(
at org.apache.felix.ipojo.junit4osgi.plugin.Junit4osgiPlugin.invokeRun(
at org.apache.felix.ipojo.junit4osgi.plugin.Junit4osgiPlugin.execute(
at org.apache.maven.plugin.DefaultPluginManager.executeMojo(
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalWithLifecycle(
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(
at org.apache.maven.DefaultMaven.doExecute(
at org.apache.maven.DefaultMaven.execute(
at org.apache.maven.cli.MavenCli.main(
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(
at sun.reflect.DelegatingMethodAccessorImpl.invoke(
at java.lang.reflect.Method.invoke(
at org.codehaus.classworlds.Launcher.launchEnhanced(
at org.codehaus.classworlds.Launcher.launch(
at org.codehaus.classworlds.Launcher.mainWithExitCode(
at org.codehaus.classworlds.Launcher.main(
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2 minutes 7 seconds
[INFO] Finished at: Sat Feb 12 23:44:07 IST 2011
[INFO] Final Memory: 233M/964M

Several other people have encountered this problem, but I didn't see a solution for this. If you know the reason for this, please add a comment. It will be very helpful :).

Thursday, February 3, 2011

Monitoring your Java application with JMX - Part 2

In the Part-1 of this article I explained the fundamentals of JMX monitoring, local and remote monitoring and provided an example on monitoring a java application locally. In Part-2 I'll explain how to monitor it remotely and how to authenticate the monitoring process.

Following system properties need to be present for remote monitoring. where portNum is the port which you want to enable the JMX connection.

You also need to add the follwing two properties.

By default, ssl and authentication is enabled. Therefore if you do not set authenticate=false, application will look for a password file and hence fail to start. If ssl is not set to false, you wont be able to connect without configuring ssl properly.

There is a special scenario where your network interface might be only listening to IPv6 addresses and hence a request from an IPv4 address failing to connect. To get rid of this, you have to add the following property too.

Lets try to monitor Tcpmon remotely. When we were monitoring Tcpmon locally we just had to start it and monitor. But in remote scenario, we have to provide the parameters mentioned above. To do this, open TCPMON_HOME/build/ It will contain,
java -cp ./tcpmon-1.0.jar $*

Now, edit it by adding the above parameters. Then it will look like,
-Djava.rmi.server.hostname=yourIP -cp ./tcpmon-1.0.jar $*

Save and run it. You will be successfully able to start Tcpmon. Then start a JConsole from a remote machine. Provide host:port for the remote process and click connect. You will be able to connect to JMX service successfully.

Lets turn to authenticating the monitoring. First, you have to set When this is set, system will be looking for a password file and an access file. You can find these two files (jmxremote.access and jmxremote.password.template) in JDK_HOME/jre/lib/management folder. Copy these two files to a place you refer. Rename jmxremote.password.template to jmxremote.password.

Following is a section extracted from the password file.
# Following are two commented-out entries.  The "monitorRole" role has
# password "QED". The "controlRole" role has password "R&D".
monitorRole QED
controlRole R&D

You can define role names (usernames) and passwords as shown above. Actions which are allowed to these roles are defined in the jmxremote.access file. Shown below is a section extracted from it.# Default access control entries:
# o The "monitorRole" role has readonly access.
# o The "controlRole" role has readwrite access and can create the standard
# Timer and Monitor MBeans defined by the JMX API.

monitorRole readonly
controlRole readwrite

You have to restrict access (make read-write-only by the owner) to the jmxremote.password file by,
chmod 0600 jmxremote.password
Then if you ls -l the files, you should see,
-rw-r--r-- 1 amila amila 3896 2011-01-17 17:45 jmxremote.access
-rw------- 1 amila amila 2854 2011-01-17 17:47 jmxremote.password
After that you have to set the system properties to point to the password and access files. Following are the properties.

Lets turn back to our Tcpmon monitoring again. Add the above two properties to and make authenticate=true. Then. should look like,
-Djava.rmi.server.hostname=yourIP -cp ./tcpmon-1.0.jar $*
Now, save and run it. Start a JConsole from a remote machine. Provide the host:port parameters, username and password and click connect. You will be able to successfully monitor Tcpmon remotely. You can try out the difference between the two access roles defined in the jmxremote.access file.

monitorRole readonly
controlRole readwrite

If you log in as the monitorRole, you will be only allowed to monitor. If you try to carry out controlRole tasks, you will be provided with a warning message as shown below.

So, now you are able to monitor your Java application using JMX successfully. For a quick recap, following are the necessary system properties to monitor it remotely.
Find more details on JMX from here.