August 22, 2013

Complete Configuration of MySQL 5 DataSource in JBoss EAP 6

Introduction

Here I will describe how to configure a MySQL 5 DataSource for JBoss EAP 6.

Install MySQL JDBC Driver as JBoss EAP 6 Module

Create a new directory under modules and a new module.xml file.

$ mkdir -p $JBOSS_HOME/modules/com/mysql/main/
$ touch $JBOSS_HOME/modules/com/mysql/main/module.xml

Download the MySQL JDBC driver and put it in the same catalog as module.xml. If necessary correct resource path below, with the downloaded jdbc driver file name.

<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="com.mysql">
  <resources>
    <resource-root path="mysql-connector-java-5.1.19.jar"/>
  </resources>
  <dependencies>
    <module name="javax.api"/>
    <module name="javax.transaction.api"/>
  </dependencies>
</module>

If this is a server installation make sure that the new directories and files get the right permission.

Configure JBoss EAP 6 DataSource

Here we will use JBoss EAP 6 in standalone mode, but if you like to use the domain mode, the configuration is the same. Open $JBOSS_HOME/standalone/configuration/standalone.xml.

        <subsystem xmlns="urn:jboss:domain:datasources:1.1">
            <datasources>

                ...                

                <datasource jndi-name="java:jboss/datasources/ExampleInfinispanDS" pool-name="ExampleInfinispanDS" enabled="true" use-java-context="true" use-ccm="true">
                    <connection-url>jdbc:mysql://localhost:3306/EXAMPLEINFINISPAN</connection-url>
                    <driver>mysql</driver>
                    <transaction-isolation>TRANSACTION_READ_COMMITTED</transaction-isolation>
                    <pool>
                        <min-pool-size>10</min-pool-size>
                        <max-pool-size>100</max-pool-size>
                        <prefill>true</prefill>
                    </pool>
                    <security>
                        <user-name>root</user-name>
                        <password>root</password>
                    </security>
                    <validation>
                        <valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker"/>
                        <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLExceptionSorter"/>
                    </validation>
                    <timeout>
                        <!-- using default timeout values -->
                    </timeout>
                    <statement>
                        <prepared-statement-cache-size>100</prepared-statement-cache-size>
                        <share-prepared-statements>true</share-prepared-statements>
                    </statement>
                </datasource>
                <drivers>

                    ...

                    <driver name="mysql" module="com.mysql">
                        <datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlDataSource</datasource-class>
                    </driver>
                </drivers>
            </datasources>
        </subsystem>

Reference

August 21, 2013

Configure UsersRolesLoginModule for JBoss EAP 6

Introduction

In this blog I will show you how to configure a simple JAAS login module, that holds username, passwords and roles in properties file. The login module for this job is org.jboss.security.auth.spi.UsersRolesLoginModule.

Finding the correct source code and documentation for the JBoss EAP 6 login modules, can be a bit tricky and the reason for that, is that the concrete implementation for them are hosted in the sister project Picketbox. For example the exact version that is shipped with JBoss EAP 6.1.0 is 4.0.17.Final-redhat-1. And the jar is located under $JBOSS_HOME/modules/system/layers/base/org/picketbox/main/.

The UsersRolesLoginModule has more to offer than I will show you here, and that is to store the password scrambled and not in clear text. But since the UsersRolesLoginModule is merely for test purpose, I will leave that out here.

Configuration

I will use JBoss EAP 6 in standalone mode, which means that the JBoss configuration file is $JBOSS_HOME/standalone/configuration/standalone.xml. Open it and add the below JAAS security-domain.

        <subsystem xmlns="urn:jboss:domain:security:1.2">
            ...
            <security-domains>
                <security-domain name="basic-policy" cache-type="default">
                    <authentication>
                        <login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="required">
                            <module-option name="usersProperties" value="${jboss.server.config.dir}/basic-user.properties"/>
                            <module-option name="rolesProperties" value="${jboss.server.config.dir}/basic-roles.properties"/>
                        </login-module>
                    </authentication>
                </security-domain>
            </security-domains>
        </subsystem>

Create Users and Assing Roles

Creating users and theirs associated roles are easy since them are located in clear plain text files located under $JBOSS_HOME/standalone/configuration/. Here I will only create one user and one role, but you can create as many as you please.

$ echo "admin=password" > $JBOSS_HOME/standalone/configuration/basic-user.properties

$ echo "admin=ROLE_FOO" > $JBOSS_HOME/standalone/configuration/basic-roles.properties

Configuration

The easiest way to test the security, is to either take an existing war project or create a new zip file add a welcome file (index.html), web.xml and jboss-web.xml. Either way the relevant configuration for the web.xml is below.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">

    ...

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Foo Pages</web-resource-name>
            <url-pattern>/*</url-pattern>
            <!-- Do not specify http-method, since then only specified http-method 
                will be authenticated, not e.g. JUNK (attack) -->
        </web-resource-collection>

        <auth-constraint>
            <description>These are the roles who have access.</description>
            <role-name>ROLE_FOO</role-name>
        </auth-constraint>

        <user-data-constraint>
            <description>This is how the user data must be transmitted.</description>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>

    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>basic-policy</realm-name>
    </login-config>

    <security-role>
        <role-name>ROLE_FOO</role-name>
    </security-role>

    <welcome-file-list>
        <welcome-file>/index.html</welcome-file>
    </welcome-file-list>

    <session-config>
        <!-- Session timeout after X MINUTES after no user interaction. -->
        <session-timeout>15</session-timeout>
        <cookie-config>
            <!-- XSS attack: make sure that cookie cannot be accessed via client 
                side scripts -->
            <http-only>true</http-only>
            <!-- CSRF attack, session hijack attack: require cookie can only be used 
                for SSL communication. -->
            <secure>true</secure>
        </cookie-config>
        <!-- Do not use URL, since then it can be stored in numerous places: browser 
            history, proxy server log, referrer logs, web logs, etc. -->
        <tracking-mode>COOKIE</tracking-mode>
    </session-config>

    <!-- Custom error pages are handled in custom ErrorReportValve in jbossweb module -->

</web-app>

And the relevant portion in jboss-web.xml.

<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
    <context-root>/example-app</context-root>
    <security-domain>java:/jaas/basic-policy</security-domain>
</jboss-web>

August 20, 2013

Configure ActiveMQ 5.8.0 to use MySQL as Persistence Mechanism

Introduction

In this blog I will show you how to change, the default persistence mechanism in Apache ActiveMQ 5.8.0 from KahaDB to instead use a RDBMS. And here I will use MySQL 5, but ActiveMQ supports most of the major vendor of RDBMS.

Install MySQL JDBC Driver

Download driver from maven central repo:
http://search.maven.org/#artifactdetails%7Cmysql%7Cmysql-connector-java%7C5.1.19%7Cjar.

Copy to $ACTIVEMQ_HOME/lib/optional/.

Create ActiveMQ database

Log into mysql and create ActiveMQ database.

$ mysql -u root -p
Enter password: 

mysql> CREATE SCHEMA `activemq` DEFAULT CHARACTER SET utf8 COLLATE utf8_swedish_ci;

Configure MySQL as persistence storage

Open the ActiveMQ configuration, $ACTIVEMQ_HOME/conf/activemq.xml, and add mysql datasource, comment/remove the default KahaDB and finally add the RDBMS persistence adapter.

<beans ...>
    ...
    </bean>

    <!-- MySql DataSource Sample Setup -->
    <bean id="mysql-ds" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/activemq"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
        <property name="maxActive" value="200"/>
        <property name="poolPreparedStatements" value="true"/>
    </bean>

    <broker ...>
        ...

        <!-- Comment out the default storage adapter
        <persistenceAdapter>
            <kahaDB directory="${activemq.data}/kahadb"/>
        </persistenceAdapter>
        -->

        <persistenceAdapter>
            <jdbcPersistenceAdapter dataSource="#mysql-ds" />
        </persistenceAdapter> 

        ...
    </broker>
    ...
</beans>

Test

Now we are ready to test the installation. Restart activemq and check the activemq log for errors, $ACTIVEMQ_HOME/data/activemq.log.

You can also open the activemq web console, to verify that things are working:
URL: http://localhost:8161/admin/
Username: admin
Password: admin

Now lets really test the installation from the activemq web console you can send message. From the web console click Send and choose to send a text message to a new queue.

Afterwards we can check that the message is sent to the queue, by clicking on Queue and our new queue foo.bar. And there see your text message.

You could also verify that the message is really persistent in MySQL by querying your database.

$mysql> SELECT ID, CONTAINER, MSGID_PROD, MSGID_SEQ FROM activemq.ACTIVEMQ_MSGS;

August 18, 2013

Configure Redelivery for ActiveMQ 5.8 Resource Adapter in JBoss EAP 6

In this blog I will show you how to setup ActiveMQ resource adapter in JBoss EAP 6 and then test different redelivery policies.

Before we begin, we need to download the latest Apache ActiveMQ binaries and unzip it. To start, stop and check status we use the activemq script located in the bin folder.

$ ACTIVEMQ_HOME/bin/activemq [start|stop|status]

After started the ActiveMQ, we can test the installation by open a web browser and open http://localhost:8161/admin/. The default username is admin and default password is admin.

Now we need to configure JBoss. In this blog we will use JBoss EAP 6.1.0. Download it and unzip it.

The next thing we need to do is to download the Apache ActiveMQ resource adapter. You can find it from maven central repo – http://search.maven.org/remotecontent?filepath=org/apache/activemq/activemq-rar/5.8.0/activemq-rar-5.8.0.rar.

JBoss EAP 6 can be run in two different modes – standalone and domain mode. In this blog we will be using standalone mode, but if you need to run JBoss in domain the below configuration is basically the same.

Now deploy the resource adapter to $JBOSS_HOME/standalone/deployment

Now we are ready to configure JBoss. Open $JBOSS_HOME/standalone/configuration/standalone.xml

        <subsystem xmlns="urn:jboss:domain:resource-adapters:1.1">
            <resource-adapters>
                <resource-adapter id="activemq-rar-5.8.0.rar">
                    <archive>
                        activemq-rar-5.8.0.rar
                    </archive>
                    <transaction-support>LocalTransaction</transaction-support>
                    <config-property name="InitialRedeliveryDelay">
                        1000
                    </config-property>
                    <config-property name="MaximumRedeliveries">
                        5
                    </config-property>
                    <config-property name="RedeliveryUseExponentialBackOff">
                        false
                    </config-property>
                    <config-property name="RedeliveryBackOffMultiplier">
                        5
                    </config-property>
                    <config-property name="ServerUrl">
                        failover:(tcp://127.0.0.1:61616)
                    </config-property>
                    <connection-definitions>
                        <connection-definition class-name="org.apache.activemq.ra.ActiveMQManagedConnectionFactory" jndi-name="java:jboss/activemq/ConnectionFactory" enabled="true" use-java-context="true" pool-name="ConnectionFactory">
                            <pool>
                                <min-pool-size>10</min-pool-size>
                                <max-pool-size>100</max-pool-size>
                                <prefill>true</prefill>
                            </pool>
                        </connection-definition>
                    </connection-definitions>
                    <admin-objects>
                        <admin-object class-name="org.apache.activemq.command.ActiveMQQueue" jndi-name="java:jboss/activemq/queue/FooQueue" enabled="true" use-java-context="true" pool-name="FooQueue">
                            <config-property name="PhysicalName">
                                FooQueue
                            </config-property>
                        </admin-object>
                    </admin-objects>
                </resource-adapter>
            </resource-adapters>
        </subsystem>

The last thing we also need is to configure mdb support for the standalone configuration.

        <subsystem xmlns="urn:jboss:domain:ejb3:1.4">
            ...
            </session-bean>
            <mdb>
                <resource-adapter-ref resource-adapter-name="activemq-rar-5.8.0.rar"/>
                <bean-instance-pool-ref pool-name="mdb-strict-max-pool"/>
            </mdb>
            <pools>
            ...
        </subsystem>

Now we are to test the installation. We do that by creating a simple MDB, that prints out incoming JMS messages and then rollbacks the MDB transaction.

package se.msc.example.mdb;

import javax.annotation.Resource;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.ejb.MessageDrivenContext;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;

@MessageDriven(name = "FooMDB", activationConfig = {
        @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
        @ActivationConfigProperty(propertyName = "destination", propertyValue = "FooQueue"),
        @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") })
public class FooMDB implements MessageListener {

    @Resource
    private MessageDrivenContext mdc;

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void onMessage(Message msg) {
        try {
            System.out.println("mdb recieved, redelivered="
                    + msg.getJMSRedelivered());
        } catch (JMSException e) {
            e.printStackTrace();
        }

        mdc.setRollbackOnly();
    }

}

As test client we can send jms message from the ActiveMQ web console

Below follows different test results for different redelivery configuration

InitialRedeliveryDelay=1000
MaximumRedeliveries=5
RedeliveryUseExponentialBackOff=false
RedeliveryBackOffMultiplier=5
                    
18:57:51,140 INFO  [stdout] (default-threads - 2) mdb recieved, redelivered=false
18:57:52,220 INFO  [stdout] (default-threads - 3) mdb recieved, redelivered=true
18:57:53,256 INFO  [stdout] (default-threads - 4) mdb recieved, redelivered=true
18:57:54,296 INFO  [stdout] (default-threads - 5) mdb recieved, redelivered=true
18:57:55,334 INFO  [stdout] (default-threads - 6) mdb recieved, redelivered=true
18:57:56,365 INFO  [stdout] (default-threads - 7) mdb recieved, redelivered=true

-----------------------------------------------------------------------------------------------

InitialRedeliveryDelay=1000
MaximumRedeliveries=5
RedeliveryUseExponentialBackOff=true
RedeliveryBackOffMultiplier=5

19:55:21,453 INFO  [stdout] (default-threads - 2) mdb recieved, redelivered=false
19:55:26,495 INFO  [stdout] (default-threads - 3) mdb recieved, redelivered=true
19:55:51,503 INFO  [stdout] (default-threads - 4) mdb recieved, redelivered=true
19:57:56,510 INFO  [stdout] (default-threads - 5) mdb recieved, redelivered=true
20:08:21,516 INFO  [stdout] (default-threads - 6) mdb recieved, redelivered=true
21:00:26,523 INFO  [stdout] (default-threads - 7) mdb recieved, redelivered=true

delta1 = 5s (calculated value 1*5)
delta2 = 25s (calculated value 5*5)
delta3 = 125s (calculated value 25*5)
delta4 = 625s (calculated value 125*5)
delta5 = 3125s (calculated value 625*5)

-----------------------------------------------------------------------------------------------

InitialRedeliveryDelay=2000
MaximumRedeliveries=5
RedeliveryUseExponentialBackOff=true
RedeliveryBackOffMultiplier=5
                    
22:28:52,542 INFO  [stdout] (default-threads - 2) mdb recieved, redelivered=false
22:29:02,598 INFO  [stdout] (default-threads - 3) mdb recieved, redelivered=true
22:29:52,604 INFO  [stdout] (default-threads - 4) mdb recieved, redelivered=true
22:34:02,609 INFO  [stdout] (default-threads - 5) mdb recieved, redelivered=true

delta1 = 10s (calculated value 2*5)
delta2 = 50s (calculated value 10*5)
delta3 = 250s (calculated value 50*5)
-----------------------------------------------------------------------------------------------    

References