Tuesday, August 9, 2011

How to get 'current' method

Hi, I need to get current method in java, one solution is of course using Thread.currentThread().getStackTrace() but its not portable because: Some virtual machines may, under some circumstances, omit one or more stack frames from the stack trace. So I used following solution, not so good but works

    public void testMethod() {

        Method currentMethod = new MethodHelper() {
            @Override
            public Method getCurrentMethod() {
                return getClass().getEnclosingMethod();
            }
        }.getCurrentMethod();
        ...................................
    }
 
    and

    public interface MethodHelper {
        Method getCurrentMethod();
    }

PS: please read getEnclosingMethod() JavaDoc it can return null as well.

Saturday, June 25, 2011

ActiveMQ messages database logging with Apache Camel

Hi, we had epayment system based on Fuse ActiveMQ and  we decided to log into DB all messages passed through ActiveMQ. I want to share my first experience with Apache Camel :)

I changed ActiveMQ configuration and used ActiveMQ feature: 'Mirrored Queues' to forward all messages to mirrored queues prefixed with qmirror. Here is ActiceMQ configuration:

<destinationInterceptors>
<mirroredQueue copyMessage = "true" postfix="" prefix="qmirror."/>
</destinationInterceptors>

So now when we have copied messages in queues with names: 'qmirror.*' and it is time to log them with Apache Camel. Thus I changed '$ACTIVEMQ_HOME/conf/camel.xml' config file in the following way:

<beans...>

    <context:component-scan base-package="info.sargis.dbloggger"/>

    <context:annotation-config/>

    <camelContext xmlns="http://camel.apache.org/schema/spring">
        <package>info.sargis.dbloggger</package>
    </camelContext>

    <bean id="lobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler"/>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
        <property name="url" value="jdbc:oracle:thin:@localhost:1521:TWMDB"/>
        <property name="username" value="activemq"/>
        <property name="password" value="ee0thaXu"/>
        <property name="maxActive" value="5"/>
        <property name="maxIdle" value="2"/>
    </bean>

    <bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">
        <property name="connectionFactory">
            <bean class="org.apache.activemq.ActiveMQConnectionFactory">
                <property name="brokerURL"
                          value="vm://localhost?create=false&amp;waitForStart=10000&amp;broker.populateJMSXUserID=true"/>
                <property name="userName" value="${activemq.username}"/>
                <property name="password" value="${activemq.password}"/>
            </bean>
        </property>
    </bean>

</beans>

and created project with structure:

|-- docs
|   `-- create_db.sql
|-- payment-dblogger.iml
|-- pom.xml
|-- README.txt
`-- src
    |-- data
    `-- main
        |-- java
        |   `-- info
        |       `-- sargis
        |           `-- dbloggger
        |               |-- DBLoggerRouteBuilder.java
        |               `-- logger
        |                   |-- DBLogger.java
        |                   |-- DBLoggerProcessor.java
        |                   `-- Logger.java
        `-- resources
            |-- log4j.properties
            `-- META-INF
                `-- spring
                    `-- camel-context.xml

note that project artifact payment-dblogger-*.jar should be deployed to '$ACTIVEMQ_HOME/webapps/camel/WEB-INF/lib'

Now its time for router :) here everything is simple as well:

package info.sargis.dbloggger;

import org.apache.camel.builder.RouteBuilder;

public class DBLoggerRouteBuilder extends RouteBuilder {
    @Override
    public void configure() {
        from("activemq:topic:qmirror.>").threads().processRef("dbLoggerProcessor");
    }
}

Tuesday, June 14, 2011

Spring RestTemplate integration with HttpComponents Client

Recently I need to use 'Basic access authentication' with RestTemplate and most of resources pointed to org.springframework.http.client.CommonsClientHttpRequest as base for RestTemplate configuration. But I decided to switch from 'Commons HttpClient' to newer library provided again by Apache community: Apache HttpComponents. So having as example org.springframework.http.client.CommonsClient* classes I started to work and after 1-2 hours it was done. You can find sources here: source and here is small example how to use. First I created class with static factory method:

package info.sargis;

import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.springframework.http.client.ClientHttpRequestFactory;

import java.net.MalformedURLException;
import java.net.URL;

public class RequestFactoryManager {
    public static ClientHttpRequestFactory createHttpClient(String service, String userName, String password) throws MalformedURLException {
        URL serviceURL = new URL(service);

        DefaultHttpClient httpClient = new DefaultHttpClient(new ThreadSafeClientConnManager());
        httpClient.getCredentialsProvider().setCredentials(
                new AuthScope(serviceURL.getHost(), serviceURL.getPort()),
                new UsernamePasswordCredentials(userName, password)
        );

        return new Commons2ClientHttpRequestFactory(httpClient);
    }
}

and here is Spring XML config:

    <bean id="clientHttpRequestFactory" class="info.sargis.RequestFactoryManager" factory-method="createHttpClient">
        <constructor-arg value="${REST_SERVICE_URL}"/>
        <constructor-arg value="${REST_USER_NAME}"/>
        <constructor-arg value="${REST_USER_PASSWORD}"/>
    </bean>

    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
        <constructor-arg ref="clientHttpRequestFactory"/>
        <property name="messageConverters">
            <list>
                <bean class="info.sargis.AtomHttpMessageConverter"/>
                <bean class="info.sargis.XMLStringHttpMessageConverter"/>
            </list>
        </property>
    </bean>

And restTemplate bean ready to use :)

Friday, April 1, 2011

Fun with 'fluent interface' and Java

Here is my story about 'fluent interface' and Java. In one project I have to compare in many places BigDecimals and other Comparable objects. So if I have:

BigDecimal requestedAmount = ...
BigDecimal paymentAmount = ...

In Java to compare BigDecimals I should use

if(requestedAmount.compareTo(paymentAmount) == 0) {

}

For me its not natural to compare numbers in such way and I decided to try to write small technical DSL, and here how looks my code now:

import static com.webbfontaine.twm.accounting.epaylog.utils.CompareDSL.*;

if (eq(valueOf(paymentAmount).comparingWith(requestedAmount))) {
}

if (ne(valueOf(paymentAmount).comparingWith(requestedAmount))) {
}

if (gt(valueOf(paymentAmount).comparingWith(requestedAmount))) {
}
.... and etc.

and here is API/DSL code:

public class CompareDSL {

    public static <T extends Comparable<T>> PairToCompare<T> valueOf(T value) {
        return new PairToCompare<T>(value);
    }

    public static <T extends Comparable<T>> boolean eq(PairToCompare<T> pairToCompare) {
        return pairToCompare.firstValue.compareTo(pairToCompare.secondValue) == 0;
    }

    public static <T extends Comparable<T>> boolean ne(PairToCompare<T> pairToCompare) {
        return !eq(pairToCompare);
    }

    public static <T extends Comparable<T>> boolean gt(PairToCompare<T> pairToCompare) {
        return pairToCompare.firstValue.compareTo(pairToCompare.secondValue) > 0;
    }

    public static <T extends Comparable<T>> boolean ge(PairToCompare<T> pairToCompare) {
        return pairToCompare.firstValue.compareTo(pairToCompare.secondValue) >= 0;
    }

    public static <T extends Comparable<T>> boolean lt(PairToCompare<T> pairToCompare) {
        return pairToCompare.firstValue.compareTo(pairToCompare.secondValue) < 0;
    }

    public static <T extends Comparable<T>> boolean le(PairToCompare<T> pairToCompare) {
        return pairToCompare.firstValue.compareTo(pairToCompare.secondValue) <= 0;
    }

    public static class PairToCompare<T extends Comparable<T>> {

        private T firstValue;
        private T secondValue;

        public PairToCompare(T firstValue) {
            this.firstValue = firstValue;
        }

        public PairToCompare<T> comparingWith(T value) {
            this.secondValue = value;
            return this;
        }

    }
}

API of course not the best one, but for me it works fine and it was fun to write it :-)

Wednesday, November 3, 2010

Start and stop VMware virtual machine as service for Linux OS

Here is my simple script for starting(non gui mode) automatically VMWare guests on system startup


[sargis@appsrv ~]# cat /etc/init.d/vm-guests
#!/bin/bash
#
# chkconfig: 235 81 29
# description: Start vmware guests.

# Source function library.
. /etc/rc.d/init.d/functions

case "$1" in
 start)
       echo -n $"Starting vmware guests: "
       su - sargis -c "/usr/bin/vmrun -T ws start /srv/vmware/dsrv/dsrv.vmx nogui"
       echo
       ;;
 stop)
       echo -n $"Shutting down vmware guests: "
       /usr/bin/vmrun -T ws stop /srv/vmware/dsrv/dsrv.vmx
       echo
       ;;
 restart|force-reload)
       stop
       start
       ;;
 *)
      echo $"Usage: $0 {start|stop|restart}"
      exit 2
esac

Sunday, October 17, 2010

How to configure Oracle/SUN JVM to send notification in case of JVM fatal error/crash

Recently we had JVM crash in production server and of course we had notified by some monitoring tools but not as fast as we could expect. So I configured our server with following JVM option:
-XX:OnError="sendjvmcrashsms". 'sendjvmcrashsms' is a Linux shell/bash file which is of course in user PATH, and here is example of the file

#! /bin/bash
echo "Production JVM crashed" | mail -s "+33000000000"


It will send mail to address with subject '+33000000000'. In our server we have configured SMS gateway which will send SMS to number(s) defined in subject, and here is docs:
-XX:OnError="<cmd args>;<cmd args>" - Run user-defined commands on fatal error