Tuesday, December 9, 2014

Install the Yeoman toolset

1. Prerequisite: Node.js and NPM should be installed in the system.

2. Install Yeoman tools
heshans@15mbp-08077.local:~/Dev$npm install --global yo bower grunt-cli

3. Check installed versions.
heshans@15mbp-08077.local:~/Dev$yo --version && bower --version && grunt --version

1.3.3

1.3.12

grunt-cli v0.1.13

Install Node.js and NPM on Mac OSX

I’m using Homebrew for the installation. If you don't have it installed, please install it.

1. Install node
heshans@15mbp-08077.local:~/Dev$brew install node

2. Check installed versions.
heshans@15mbp-08077.local:~/Dev$node -v

v0.10.33

heshans@15mbp-08077.local:~/Dev$npm -v

2.1.8

3. Update Homebrew.
heshans@15mbp-08077.local:~/Dev$brew update 

Already up-to-date.

4. Upgrade Node.
heshans@15mbp-08077.local:~/Dev$brew upgrade node

Wednesday, October 15, 2014

How to find which method called the current method at runtime


I’m using the following helper class to find which method called the current method (at runtime.)

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

public class TraceHelper {
    private volatile static Method m;
    private static Throwable t;

    public TraceHelper() {
        try {
            m = Throwable.class.getDeclaredMethod("getStackTraceElement", int.class);
            AccessController.doPrivileged(
                    new PrivilegedAction() {
                        public Object run() {
                            m.setAccessible(true);
                            return null;
                        }
                    }
            );
            t = new Throwable();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public String getMethodName(final int depth, boolean useNew) {
        return getMethod(depth, t != null && !useNew ? t : new Throwable());
    }

    public String getMethod(final int depth, Throwable t) {
        try {
            StackTraceElement element = (StackTraceElement) m.invoke(t, depth + 1);
            return element.getClassName() + "$" + element.getMethodName();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

}
Then I use the following code inside my aspect to get the name of the method which called my current (executing) method.
String previousMethodName = new TraceHelper().getMethodName(2, false);

Include/exclude sources when using aspect-maven-plugin


AspectJ mavn plugin will add all .java and .aj files in the project source directories by default. By using <include/> and <exclude/> tags, you can add filtering on top of that. 


            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.5</version>
                <configuration>
                    <complianceLevel>1.7</complianceLevel>
                    <source>1.7</source>
                    <target>1.7</target>

                    <sources>
                        <source>
                            <!--<basedir>src/main/java</basedir>-->
                            <!--<includes>-->
                                <!--<include>**/TransationAspect.java</include>-->
                            <!--</includes>-->
                            <excludes>
                                <exclude>**/DcXferHandler.java</exclude>
                                <!--<exclude>**/ChunkingSqlSerActor.java</exclude>-->
                            </excludes>
                        </source>
                    </sources>
                </configuration>
                <executions>
                    <execution>
                        <!--<phase>process-sources</phase>-->
                        <goals>
                            <goal>compile</goal>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

Tuesday, October 14, 2014

Stackmap frame errors when building the aspectj project with Java 1.7


I had a project which used aspectj and it was building fine with Java 1.6. When I updated it to Java 1.7 I saw the following error.

[INFO] Molva the Destroyer Aspects ....................... FAILURE [2.324s]
[INFO] Molva The Destroyer Client ........................ SKIPPED
[INFO] Molva The Destroyer Parent ........................ SKIPPED
[INFO] Molva The Destroyer Distribution .................. SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.424s
[INFO] Finished at: Tue Oct 14 11:16:19 PDT 2014
[INFO] Final Memory: 12M/310M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.1:java (default) on project molva-the-destroyer-aspects: An exception occured while executing the Java class. Expecting a stackmap frame at branch target 30
[ERROR] Exception Details:
[ERROR] Location:
[ERROR] com/concur/puma/molva/aspects/TestTarget.main([Ljava/lang/String;)V @12: invokestatic
[ERROR] Reason:
[ERROR] Expected stackmap frame at this location.
[ERROR] Bytecode:
[ERROR] 0000000: 2a4d b200 5e01 012c b800 644e b800 c62d
[ERROR] 0000010: b600 ca2c 2db8 00bb 2db8 00bf 57b1 3a04
[ERROR] 0000020: b800 c62d 1904 b600 ce19 04bf
[ERROR] Exception Handler Table:
[ERROR] bci [12, 30] => handler: 30
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

My maven configuration looked like below.
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.6.5</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.perf4j</groupId>
            <artifactId>perf4j</artifactId>
            <version>0.9.16</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.2</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.1</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>java</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <mainClass>com.concur.puma.molva.aspects.TestTarget</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

Fix 

The default compliance level for aspectj-maven-plugin is 1.4 according to http://mojo.codehaus.org/aspectj-maven-plugin/compile-mojo.html#complianceLevel. Since I did not have that tag specified, the build was using the default value. Once I inserted the tag into the configuration, the build was successful.

Compile aspectj project containing Java 1.7 Source


Following maven configuration let’s you compile a project with Java 1.7 source.
<dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <!--<version>1.6.5</version>-->
            <version>1.8.2</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.7</version>
                <configuration>
                    <complianceLevel>1.7</complianceLevel>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
                <executions>
                    <execution>
                        <!--<phase>process-sources</phase>-->
                        <goals>
                            <goal>compile</goal>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

Tuesday, September 23, 2014

Jmeter plugins for Apache Jmeter

I came across Jmeter-plugins project today and tried it out. It has a nice set of addons to support/complement existing functionality of Jmeter.

Thursday, March 27, 2014

Installing R on Mac OS X

1) Install Homebrew in your system.

2) Download and install XQuartz (Homebrew does not package XQuartz and it is needed for step 3. Therefore install XQuartz.)

3) Install Fortran and R.
heshans@15mbp-08077:/tmp$ brew update

heshans@15mbp-08077:/tmp$ brew tap homebrew/science

heshans@15mbp-08077:/tmp$ brew install gfortran r 

4) Verify the installation by running R.
heshans@15mbp-08077:/tmp$ R

R version 3.0.3 (2014-03-06) -- "Warm Puppy"
Copyright (C) 2014 The R Foundation for Statistical Computing
Platform: x86_64-apple-darwin13.1.0 (64-bit)

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type 'license()' or 'licence()' for distribution details.

  Natural language support but running in an English locale

R is a collaborative project with many contributors.
Type 'contributors()' for more information and
'citation()' on how to cite R or R packages in publications.

Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.

Tuesday, March 25, 2014

Custom Log Formatter

Following is the source for a custom log formatter.

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.LogRecord;

public class CustomFormatter extends Formatter {

    private static final DateFormat df = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss.SSS");

    public String format(LogRecord record) {
        StringBuilder builder = new StringBuilder(1000);
        builder.append(df.format(new Date(record.getMillis()))).append(" - ");
        builder.append("[").append(record.getSourceClassName()).append(".");
        builder.append(record.getSourceMethodName()).append("] - ");
        builder.append("").append(record.getLevel()).append(" - ");
        builder.append(formatMessage(record));
        builder.append("\n");
        return builder.toString();
    }

    public String getHead(Handler h) {
        return super.getHead(h);
    }

    public String getTail(Handler h) {
        return super.getTail(h);
    }
}

Following is the way how the log messages will turn up in your log file.

25/03/2014 08:46:17.770 - [com.company.util.memcache.EntityThreadTask.setDataToMemcache] - INFO - thread05 compositekey set time : 5 ms
25/03/2014 08:46:17.781 - [com.company.util.memcache.EntityThreadTask.setDataToMemcache] - INFO - thread03 compositekey set time : 11 ms
25/03/2014 08:46:17.783 - [com.company.util.memcache.EntityThreadTask.setDataToMemcache] - INFO - thread05 compositekey set time : 12 ms
25/03/2014 08:46:17.785 - [com.company.util.memcache.EntityThreadTask.setDataToMemcache] - INFO - thread03 compositekey set time : 4 ms
25/03/2014 08:46:17.787 - [com.company.util.memcache.EntityThreadTask.setDataToMemcache] - INFO - thread05 compositekey set time : 4 ms

Monday, March 10, 2014

Fixing BSFException: unable to load language: java

I was using JMeter to execute BeanShell scripts that I have written and came across this exception. I had to waste sometime to find out what was the exact issue. Although I copied the BSF jar to the JMeter lib directory, it was not sufficient. When I added the bsh-bsf-2.0b4.jar, the script started running successfully. 

I thought someone else might find this tip useful, therefore blogging it.

Thursday, March 6, 2014

Fixing java.lang.ClassNotFoundException: org.apache.bsf.engines.java.JavaEngine

When using JMeter’s Java request sampler, I started seeing the below error.
2014/03/06 09:46:39 ERROR - org.apache.bsf.BSFManager: Exception : java.lang.ClassNotFoundException: org.apache.bsf.engines.java.JavaEngine
 at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
 at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
 at org.apache.bsf.BSFManager.loadScriptingEngine(BSFManager.java:693)
 at org.apache.jmeter.util.BSFTestElement.processFileOrScript(BSFTestElement.java:98)
 at org.apache.jmeter.visualizers.BSFListener.sampleOccurred(BSFListener.java:51)
 at org.apache.jmeter.threads.ListenerNotifier.notifyListeners(ListenerNotifier.java:84)
 at org.apache.jmeter.threads.JMeterThread.notifyListeners(JMeterThread.java:783)
 at org.apache.jmeter.threads.JMeterThread.process_sampler(JMeterThread.java:443)
        at org.apache.jmeter.threads.JMeterThread.run(JMeterThread.java:257)

Following steps will resolve this issue.

1. Remove existing bsf jar from the jmeter/lib directory
heshans@15mbp-08077:~/Dev/tools$ rm apache-jmeter-2.11/lib/bsf-2.4.0.jar

2. Download and extract BSF http://wi.wu-wien.ac.at/rgf/rexx/bsf4rexx/current/BSF4Rexx_install.zip.

3. Copy the following two jars to the jmeter/lib directory.
heshans@15mbp-08077:~/Dev/tools$ cp bsf4rexx/bsf-rexx-engine.jar apache-jmeter-2.11/lib/ 
heshans@15mbp-08077:~/Dev/tools$ cp bsf4rexx/bsf- apache-jmeter-2.11/lib/

Thursday, February 27, 2014

Fixing java.lang.NoClassDefFoundError: org/codehaus/classworlds/Launcher

I came across this error after I installed a new version of maven.
$ mvn -version
java.lang.NoClassDefFoundError: org/codehaus/classworlds/Launcher
Caused by: java.lang.ClassNotFoundException: org.codehaus.classworlds.Launcher
        at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Could not find the main class: org.codehaus.classworlds.Launcher.  Program will exit.
Exception in thread "main"
The issue was with having two MAVEN_HOME locations (two versions) in the "path" variable. Once I removed a one, the issue resolved.
$ mvn -version
Apache Maven 3.1.1

Monday, February 24, 2014

Fixing mysql replication errors in a master/slave setup

If you have a mysql master/slave replication setup and have run into replication errors, you can follow the below instructions to fix up the replication break and sync up the data.
1) Stop mysql on the slave.
service mysql stop
2) Login to the master.

3) Lock the master by running the following command
mysql> flush tables with read lock;
NOTE: No data can be written at this time to the master, so be quick in the following steps if your site is in production. It is important that you do not close mysql or this running ssh terminal. Login to a separate ssh terminal for the next part.

4) Now, in a separate ssh screen, type the following command from the master mysql server.
rsync -varPe ssh /var/lib/mysql root@IP_ADDRESS:/var/lib/ —delete-after
5) After this is done, now you must get the binlog and position from the master before you unlock the tables. Run the following command on master
mysql> show master status\G;
Then you’ll get some information on master status. You need the file and the position because that’s what you’re going to use on the slave in a moment. See step 10 on how this information is used, but please do not skip to step 10.

6) Unlock the master. It does not need to be locked now that you have the copy of the data and the log position.
mysql> unlock tables;
7) Login to the slave now via ssh. First remove the two files : /var/lib/mysql/master.info and /var/lib/mysql/relay-log.info

8) Start mysql on the slave.
service mysqld start
9) Immediately login to mysql and stop slave
mysql> slave stop; 
10) Now, you have to run the following query filling in the information from the show master status above (Step 5.)
mysql> CHANGE MASTER TO MASTER_HOST=MASTER_IP,
mysql> MASTER_USER=‘replicate’, MASTER_PASSWORD=‘replicate’,
mysql> MASTER_LOG_FILE=‘mysql-bin.000001’, MASTER_LOG_POS=1234512351;
11) Now start the slave.
mysql > slave start
12) Check slave status.
mysql> show slave status\G;

Thursday, February 20, 2014

XML to XML tranformation using XSLT

In this example I am transforming an XML using XSLT by modifying certain child elements. In coming XML message:
<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="/xsl/error.xsl"?>
<outtask_error>
    <server>
        <name>RSDC-C12</name>
    </server>
    <application>
        <name>Jobs</name>
        <version>2012_06_15</version>
        <prod_status>qa</prod_status>
        <datacenter_location>rtwa3</datacenter_location>
        <request_id>n6dft440-8049-4dff-982a-ee05abc8433</request_id>
    </application>
    <error time="2014-02-06T20:01:05" timezone="Pacific Standard Time">
        <error_id>aab10-825-4a52d-a261-7a845262f</error_id>
        <error_default_source>ICSYC</error_default_source>
        <request_id>b2263a40-8049-4dff-942a-ee05ef3f8433</request_id>
        <error_source>ICSync</error_source>
        <error_description>Connection Entity:abc no DB name is not configured</error_description>
        <stack_trace>at Company.Core.Sync.GetConnectionInfo...
        </stack_trace>
    </error>
    <server_variables>
        <param name="SERVER_NAME">RSDC-C12</param>
        <param name="SCRIPT_NAME">C:\Sync.exe</param>
        <param name="QUERY_STRING">Sync.exe Day1</param>
    </server_variables>
    <Error_Context>
        <param name="databasename">Company_MT</param>
        <param name="error_defaultsource">SYS</param>
        <param name="error_defaultapplicationname">Jobs</param>
        <param name="requestid">b8943a40-1349-4dff-232a-ee05ef523452342f</param>
        <param name="dbservername">fabc-sql02,1420</param>
    </Error_Context>
</outtask_error>
XSLT for the transformation:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="outtask_error/server_variables">
        <server_variables>
            <xsl:for-each select="param">
                <xsl:text disable-output-escaping="yes"><</xsl:text><xsl:value-of select="./@name"/><xsl:text disable-output-escaping="yes">></xsl:text>
                <xsl:value-of select="."/>
                <xsl:text disable-output-escaping="yes"><</xsl:text>/<xsl:value-of select="./@name"/><xsl:text disable-output-escaping="yes">></xsl:text>
            </xsl:for-each>
        </server_variables>
    </xsl:template>

    <xsl:template match="outtask_error/Error_Context">
        <Error_Context>
            <xsl:for-each select="param">
                <xsl:text disable-output-escaping="yes"><</xsl:text><xsl:value-of select="./@name"/><xsl:text disable-output-escaping="yes">></xsl:text>
                <xsl:value-of select="."/>
                <xsl:text disable-output-escaping="yes"><</xsl:text>/<xsl:value-of select="./@name"/><xsl:text disable-output-escaping="yes">></xsl:text>
            </xsl:for-each>
        </Error_Context>
    </xsl:template>

</xsl:stylesheet>
Out going XML:
<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="/xsl/error.xsl"?><outtask_error>
    <server>
        <name>RSDC-C12</name>
    </server>
    <application>
        <name>Jobs</name>
        <version>2012_06_15</version>
        <prod_status>qa</prod_status>
        <datacenter_location>rtwa3</datacenter_location>
        <request_id>n6dft440-8049-4dff-982a-ee05abc8433</request_id>
    </application>
    <error time="2014-02-06T20:01:05" timezone="Pacific Standard Time">
        <error_id>aab10-825-4a52d-a261-7a845262f</error_id>
        <error_default_source>ICSYC</error_default_source>
        <request_id>b2263a40-8049-4dff-942a-ee05ef3f8433</request_id>
        <error_source>ICSync</error_source>
        <error_description>Connection Entity:abc no DB name is not configured</error_description>
        <stack_trace>at Company.Core.Sync.GetConnectionInfo...
        </stack_trace>
    </error>
    <server_variables><SERVER_NAME>RSDC-C12</SERVER_NAME><SCRIPT_NAME>C:\Sync.exe</SCRIPT_NAME><QUERY_STRING>Sync.exe Day1</QUERY_STRING></server_variables>
    <Error_Context><databasename>Company_MT</databasename><error_defaultsource>SYS</error_defaultsource><error_defaultapplicationname>Jobs</error_defaultapplicationname><requestid>b8943a40-1349-4dff-232a-ee05ef523452342f</requestid><dbservername>fabc-sql02,1420</dbservername></Error_Context>
</outtask_error>

Thursday, January 30, 2014

Aspect oriented programming with Java

I started working with AspectJ and Perf4J recently. I did not have any prior AOP experience. I was looking for an example which did not use Spring AOP but I did not find a good sample which I could use to get my work done. Therefore, once I completed my project, thought of writing this sample up. There are a lot of tutorials out there which describes what AOP is. Therefore, I’m not going to introduce it here. You can do a Google search and find it out.

What I wanted was to measure the method runtimes without doing any modifications to the existing source. AspectJ helped me to achieve that.

Following are my sample source code. Following is my test class which I'm using to measure method runtimes.
import org.apache.log4j.Logger;

public class TestTarget {

    static Logger logger = Logger.getLogger(TestTarget.class);

    public static void main(String[] args) throws Exception {
        // Test case 01
        testCountFast(1000);

        // Test case 02
        testCountSlow(1000);

    }

    public static void testCountSlow(int value) {
        count(value,5);
    }

    public static void testCountFast(int value) {
        count(value,0);
    }

    private static void count(int value, int delay) {
        for (int i=0;i<value;i++) {
            try {
                Thread.sleep(delay);
            } catch (Exception e) {
                logger.error("Error occurred while sleeping", e);
            }
        }
    }

}
Following is my Aspect class which uses AspectJ and Perf4J.
import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.perf4j.StopWatch;
import org.perf4j.log4j.Log4JStopWatch;

@Aspect
public class Perf4JAspect {
    static Logger logger = Logger.getLogger(Perf4JAspect.class);

    @Around("execution (* com.company.molva.aspectj.TestTarget.test*(..))")
    public Object measureExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        logger.info(MolvaLoggingUtil.getCurrentDateTime()
                + " MainAspect.measureExecutionTime() called on " + joinPoint.getSignature());

        long startNanoTime = System.nanoTime();
        StopWatch stopWatch = new Log4JStopWatch();
        Object proceed = joinPoint.proceed();
        stopWatch.stop(joinPoint.getSignature().toLongString());

        long endNanoTime = System.nanoTime();
        long executionNanoTime = endNanoTime - startNanoTime;
        logger.info(MolvaLoggingUtil.getCurrentDateTime() + " "
                + joinPoint.getSignature()+" took "+ executionNanoTime/1000000.0 +"ms");
        return proceed;
    }
}
My aop.xml configuration is as follows.
<aspectj>
    <aspects>
        <aspect name="com.company.molva.aspectj.MainAspect"/>
        <aspect name="com.company.molva.aspectj.Perf4JAspect"/>
    </aspects>

    <weaver options="-verbose">
        <include within="com.aspectj.*"/>
    </weaver>
</aspectj>
My log4j.xml looks as follows.
 
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration debug="false" xmlns:log4j="http://jakarta.apache.org/log4j/">

    <appender name="aspectjFileAppender" class="org.apache.log4j.FileAppender">
        <param name="File" value="aspectj_stats.log"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%m%n"/>
        </layout>
    </appender>
 
    <appender name="CoalescingStatistics"
              class="org.perf4j.log4j.AsyncCoalescingStatisticsAppender">
        <param name="TimeSlice" value="10000"/>
        <appender-ref ref="fileAppender"/>
    </appender>

    <appender name="fileAppender" class="org.apache.log4j.FileAppender">
        <param name="File" value="perf_stats.log"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%m%n"/>
        </layout>
    </appender>

     <logger name="org.perf4j.TimingLogger" additivity="false">
        <level value="INFO"/>
        <appender-ref ref="CoalescingStatistics"/>
    </logger>

    <root>
        <level value="INFO"/>
        <appender-ref ref="aspectjFileAppender"/>
    </root>
    
</log4j:configuration>
Once the sample completes running, I get the following logs at my log files.
aspectj_stats.log:
2014-01-30 13:19:25 MainAspect.measureExecutionTime() called on void com.company.molva.aspectj.TestTarget.testCountFast(int)
2014-01-30 13:19:25 void com.company.molva.aspectj.TestTarget.testCountFast(int) took 0.904ms
2014-01-30 13:19:25 MainAspect.measureExecutionTime() called on void com.company.molva.aspectj.TestTarget.testCountSlow(int)
2014-01-30 13:19:31 void com.company.molva.aspectj.TestTarget.testCountSlow(int) took 5608.996ms
perf_stats.log:
Performance Statistics   2014-01-30 13:19:20 - 2014-01-30 13:19:30
Tag                                                                        Avg(ms)         Min         Max     Std Dev       Count
public static void com.company.molva.aspectj.TestTarget.testCountFast(int)     0.0           0           0         0.0           1
public static void com.company.molva.aspectj.TestTarget.testCountSlow(int)  5608.0        5608        5608         0.0           1
As you can see, we can use AspectJ and Perf4J to generate some nice statistics.

Java library to convert XML to JSON

Recently I wanted to convert some XMLs to JSON messages. I came across this library called JSON-Java and found it very useful.
import org.json.JSONException;
import org.json.JSONObject;
import org.json.XML;

public class Main {

    public static int PRETTY_PRINT_INDENT_FACTOR = 4;
    public static String TEST_XML_STRING =
            "\n" +
                    "\n" +
                    "Belgian Waffles\n" +
                    "$5.95\n" +
                    "\n" +
                    "Two of our famous Belgian Waffles with plenty of real maple syrup\n" +
                    "\n" +
                    "650\n" +
                    "\n" +
                    "\n" +
                    "Strawberry Belgian Waffles\n" +
                    "$7.95\n" +
                    "\n" +
                    "Light Belgian waffles covered with strawberries and whipped cream\n" +
                    "\n" +
                    "900\n" +
                    "\n" +
                    "";

    public static void main(String[] args) {
        try {
            JSONObject xmlJSONObj = XML.toJSONObject(TEST_XML_STRING);
            String jsonPrettyPrintString = xmlJSONObj.toString(PRETTY_PRINT_INDENT_FACTOR);
            System.out.println(jsonPrettyPrintString);
        } catch (JSONException je) {
            System.out.println(je.toString());
        }
    }
}
The XML:
<breakfast_menu>
<food>
<name>Belgian Waffles</name>
<price>$5.95</price>
<description>
Two of our famous Belgian Waffles with plenty of real maple syrup
</description>
<calories>650</calories>
</food>
<food>
<name>Strawberry Belgian Waffles</name>
<price>$7.95</price>
<description>
Light Belgian waffles covered with strawberries and whipped cream
</description>
<calories>900</calories>
</food>
</breakfast_menu>
JSON:
{"breakfast_menu": {"food": [
    {
        "price": "$5.95",
        "description": "Two of our famous Belgian Waffles with plenty of real maple syrup",
        "name": "Belgian Waffles",
        "calories": 650
    },
    {
        "price": "$7.95",
        "description": "Light Belgian waffles covered with strawberries and whipped cream",
        "name": "Strawberry Belgian Waffles",
        "calories": 900
    }
]}}