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 :)