Skip to main content

Multi Module Maven Project Using Assembly Plugin

 Maven is a very flexible and powerful technology. Anyone in Java software industry is suggested to make use of it.


This document will describe multi module maven project. Assembly plugin is used to merge outputs of modules into one jar.

Provided project is a full fledged Java project which uses spring framework for dependency injection, hibernate for ORM. The project comes with several basic classes to make use of the project architecture and show use of some usefull patterns. All project files are attached to the end of this document.

1.      Parent Pom


Lists all submodules and uses maven-assembly-module.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mygroup</groupId>
    <artifactId>myproject</artifactId>
    <packaging>pom</packaging>
    <version>1.0</version>

    <build>
        <directory>target</directory>
        <outputDirectory>target/myproject/classes</outputDirectory>
        <testOutputDirectory>target/test-classes</testOutputDirectory>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
        <pluginManagement>
            <plugins>
                <plugin>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <version>2.4</version>
                    <configuration>
                        <descriptors>
                            <descriptor>src/assemble/bin.xml</descriptor>
                        </descriptors>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

    <modules>
        <module>myproject-assembly</module>
        <module>myproject-module1</module>
        <module>myproject-module2</module>
    </modules>

    <properties>
        <spring.version>3.2.3.RELEASE</spring.version>
        <hibernate.version>3.2.0.ga</hibernate.version>
        <hibernate.annotations.version>3.2.0.ga</hibernate.annotations.version>
        <hibernate.validator.version>4.0.2.GA</hibernate.validator.version>
        <logback.version>1.0.13</logback.version>
        <slf4j.version>1.7.5</slf4j.version>
        <junit.version>4.11</junit.version>
        <spring.security.version>3.2.0.RELEASE</spring.security.version>
        <jsf.version>2.2.9</jsf.version>
    </properties>


    <repositories>
        <repository>
            <id>spring</id>
            <name>Spring repository</name>
            <url>http://s3.amazonaws.com/maven.springframework.org/release</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>mvnrepository</id>
            <name>Spring repository</name>
            <url>http://mvnrepository.com/artifact/</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

</project>

2.      Module1


Module1 comes with basic constructs. First of all project wise dependencies are listed in module1 pom.



<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <parent>
        <artifactId>myproject</artifactId>
        <groupId>com.mygroup</groupId>
        <version>1.0</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <artifactId>myproject-module1</artifactId>
    <packaging>jar</packaging>
    <version>1.0</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- data source -->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>

        <!-- persistence -->
        <dependency>
            <groupId>javax.persistence</groupId>
            <artifactId>persistence-api</artifactId>
            <version>1.0</version>
        </dependency>

        <!-- hibernate jars-->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-annotations</artifactId>
            <version>${hibernate.annotations.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate</artifactId>
            <version>${hibernate.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>commons-logging</artifactId>
                    <groupId>commons-logging</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>javassist</groupId>
            <artifactId>javassist</artifactId>
            <scope>compile</scope>
            <version>3.3</version>
        </dependency>

        <!-- end of hibernate jars-->

        <!-- google generic hibernate dao-->
        <dependency>
            <groupId>com.googlecode.genericdao</groupId>
            <artifactId>dao-hibernate</artifactId>
            <version>1.1.0</version>
            <scope>compile</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.hibernate</groupId>
                    <artifactId>hibernate-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- end of persistence -->


        <!-- jdbc connectors -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.15</version>
        </dependency>


        <!-- Logging with SLF4J & LogBack -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>${logback.version}</version>
            <scope>runtime</scope>
        </dependency>
        <!-- for log4j support -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>log4j-over-slf4j</artifactId>
            <version>${slf4j.version}</version>
        </dependency>

        <!-- Unit Testing -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>


Module1 comes with three spring configuration files:
·         applicationContext-core.xml : Loads property file and other config files.
·         applicationContext-jmx.xml : Contains JMX configuration for remote monitoring.
·         persistence-config-core.xml : Contains spring transaction management declerations, database connection pool definitions and hibernate configurations.

2.A. applicationContext-core.xml


applicationPropertiesDir should be passed to application as a JVM argument.
               

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- Load Property File -->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="ignoreResourceNotFound" value="true"/>
        <property name="locations">
            <list>
                <!-- set at startup as -DapplicationPropertiesDir=dir-to-props-folder -->
                <value>file:${applicationPropertiesDir}application.properties</value>
            </list>
        </property>
    </bean>

    <import resource="persistence-config-core.xml"/>
    <import resource="applicationContext-jmx.xml"/>
   
</beans>


2.B. persistenceContext-core.xml


Placeholders are replaced with values from properties file. packagesToScan should be containing list of packages that may contain Entity classes. Make sure hibernate.hbm2ddl.auto property is set to be empty (in properties file) for production environments. Similarly jdbc:initialize-database should be disabled for production environments. jdbc:initialize-database can be used for test environments to populate db tables with test data.


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
       xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
       xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">


    <!-- configure spring managed transactions -->
    <tx:annotation-driven mode="proxy" proxy-target-class="true" transaction-manager="transactionManager"/>

    <!-- Data Source Definition-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
          destroy-method="close">
        <property name="driverClass" value="${database.connection.driver}"/>
        <property name="jdbcUrl" value="${database.connection.url}"/>
        <property name="user" value="${database.connection.username}"/>
        <property name="password" value="${database.connection.password}"/>
        <property name="acquireIncrement" value="${database.connection.acquireIncrement}"/>
        <property name="initialPoolSize" value="${database.connection.initialPoolSize}"/>
        <property name="maxIdleTime" value="${database.connection.maxIdleTime}"/>
        <property name="maxPoolSize" value="${database.connection.maxPoolSize}"/>
        <property name="maxStatements" value="${database.connection.maxStatements}"/>
        <property name="minPoolSize" value="${database.connection.minPoolSize}"/>
        <property name="idleConnectionTestPeriod"
                  value="${database.connection.idleConnectionTestPeriod}"/>
        <property name="testConnectionOnCheckout" value="true"/>
        <property name="preferredTestQuery" value="${database.connection.preferredTestQuery}"/>
        <property name="maxAdministrativeTaskTime"
                  value="${database.connection.maxAdministrativeTaskTime}"/>
        <property name="unreturnedConnectionTimeout"
                  value="${database.connection.unreturnedConnectionTimeout}"/>
        <property name="debugUnreturnedConnectionStackTraces"
                  value="${database.connection.debugUnreturnedConnectionStackTraces}"/>
    </bean>


    <!-- Hibernate SessionFactory Definition -->
    <bean id="sessionFactory"
          class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="packagesToScan">
            <list>
                <value>com.mygroup.myproject.module1.model</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.id.new_generator_mappings">true</prop>
                <prop key="hibernate.cglib.use_reflection_optimizer">true</prop>
                <prop key="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</prop>

                <!-- important to avoid connection leaks  -->
                <prop key="hibernate.connection.release_mode">after_transaction</prop>
                <!-- encoding-->
                <prop key="hibernate.connection.CharSet">utf8</prop>
                <prop key="hibernate.connection.characterEncoding">utf8</prop>
                <prop key="hibernate.connection.useUnicode">true</prop>

                <!-- tracking -->
                <prop key="generate_statistics">${hibernate.generate.statistics}</prop>

            </props>
        </property>
    </bean>

    <!-- Spring Data Access Exception Translator Defintion -->
    <bean id="jdbcExceptionTranslator"
          class="org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- Hibernate Template Definition -->
    <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
        <property name="sessionFactory" ref="sessionFactory"/>
        <property name="jdbcExceptionTranslator" ref="jdbcExceptionTranslator"/>
    </bean>


    <!-- Hibernate Transaction Manager Definition -->
    <bean id="transactionManager"
          class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <jdbc:initialize-database enabled="${db.init.enabled}" data-source="dataSource">
        <jdbc:script location="file:${applicationPropertiesDir}${db.init.file}"/>
        <!-- encoding="UTF-8" -->
    </jdbc:initialize-database>
</beans>


2.C. applicationContext-jmx.xml


Contains JMX configuration. Make sure JVM is started with relevant parameters (listed below) for remote monitoring process.
-Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.port=3309 -Djava.rmi.server.hostname=HOST_IP
HOST_IP shold be replaced with IP value of host system. Jconsole, JvisualVM or JMC can be used to remote monitor java processes. For remote monitoring a java process details, loot at this page.


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- spring based jmx export -->
    <bean id="jmxExporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
        <property name="registrationPolicy" value="FAIL_ON_EXISTING"/>
        <property name="beans">
            <map>
                <entry key="org.hibernate.jmx:type=Statistics,name=hibernateStatistics" value-ref="hibernateStatisticsMBean"/>
                <!-- additional/Custom JMX beans  goes here -->
            </map>
        </property>
    </bean>

    <bean id="hibernateStatisticsMBean" class="org.hibernate.jmx.StatisticsService">
        <property name="statisticsEnabled" value="${hibernate.generate.statistics}"/>
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

</beans>

3.      Module2


Module contains real bussiness. Service beans which contains bussiness tasks are defined here. Also application entry point (main method) is found in this module. Typically depends on first module.


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <parent>
        <artifactId>myproject</artifactId>
        <groupId>com.mygroup</groupId>
        <version>1.0</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <artifactId>myproject-module2</artifactId>
    <packaging>jar</packaging>
    <version>1.0</version>
   
    <dependencies>
        <dependency>
            <groupId>com.mygroup</groupId>
            <artifactId>myproject-module1</artifactId>
            <version>1.0</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
    </dependencies>

</project>


Logback configration file is provided. It basically outputs to two files. One file contains all log information, other file only collects warning or error level logs. Configuration file is scanned at every 60 seconds, if modified changes are loaded. jmxConfigurator , as name implies exports JMX beans for remote monitoring. Log files are rotated daily. Also rotated if max file size is reached.  Rotated log files are compressed. As history, records of  last 60 days are kept.


<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds">
    <jmxConfigurator/>
    <property name="log.dir" value="logs"/>
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <Target>System.out</Target>
        <encoder>
            <pattern>%date{HH:mm:ss.SSS} [%thread] %-5level %logger{35} - %msg%n</pattern>
        </encoder>
    </appender>
    <appender name="defaultLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>${log.dir}/catchAll.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- daily rollover -->
            <fileNamePattern>${log.dir}/%d{yyyy-MM,aux}/catchAll.%d{yyyy-MM-dd}.%i.zip</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- or whenever the file size reaches 500MB -->
                <maxFileSize>500MB</maxFileSize>
                <maxIndex>100</maxIndex>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!-- keep 30 days' worth of history -->
            <maxHistory>360</maxHistory>
        </rollingPolicy>

        <encoder>
            <pattern>%date{HH:mm:ss.SSS} [%thread] %-5level %logger{35} - %msg%n</pattern>
        </encoder>

    </appender>


    <appender name="errorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>${log.dir}/error.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- daily rollover -->
            <fileNamePattern>${log.dir}/%d{yyyy-MM,aux}/error.%d{yyyy-MM-dd}.%i.zip</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- or whenever the file size reaches 500MB -->
                <maxFileSize>500MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!-- keep 30 days' worth of history -->
            <maxHistory>360</maxHistory>
        </rollingPolicy>

        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>WARN</level>
        </filter>
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{35} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="DEBUG">
        <appender-ref ref="defaultLog"/>
        <appender-ref ref="errorLog"/>
        <!--appender-ref ref="stdout"/-->
    </root>

    <!-- suppress c3p0 logs -->
    <logger name="com.mchange.v2.log.MLog" level="info"/>
</configuration>

4.      Module Assembly


Assembly module, assembles other modules into one jar file. All dependent jars are copied to target/lib dir. A bat file is provied to run the application. One thing to note with bat file is, it requires the existence of properties-directory as applicationPropertiesDir in project root.


<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
    <id>myproject-assembly</id>
    <formats>
        <format>jar</format>
    </formats>
    <includeBaseDirectory>false</includeBaseDirectory>
    <dependencySets>
        <dependencySet>

            <!-- Enable access to all projects in the current multimodule build! -->
            <useProjectArtifact>true</useProjectArtifact>
            <!-- Now, select which projects to include in this module-set. -->
            <includes>
                <include>com.mygroup:*</include>
            </includes>

            <outputDirectory>/</outputDirectory>
            <unpack>true</unpack>

        </dependencySet>
    </dependencySets>
</assembly>



Assembly module pom executes assembling process and copies all dependencies to target/lib directory.


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>myproject</artifactId>
        <groupId>com.mygroup</groupId>
        <version>1.0</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <artifactId>myproject-assembly</artifactId>
    <packaging>pom</packaging>

    <dependencies>
        <dependency>
            <artifactId>myproject-module2</artifactId>
            <groupId>com.mygroup</groupId>
            <!-- Before first build 'LATEST' may cause errors, replace it with a valid version number and build.
            After  a successful build, LATEST is good to go again. -->
            <version>LATEST</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <executions>
                    <execution>
                        <id>make-bundles</id>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <phase>package</phase>
                        <configuration>
                            <finalName>${project.build.finalName}</finalName>
                            <appendAssemblyId>false</appendAssemblyId>
                            <descriptors>
                                <descriptor>src/assembly/bin.xml</descriptor>
                            </descriptors>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
             <plugin>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>install</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/lib</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>


And finally run.bat for launching the application.

java -cp .;target/myproject-assembly-1.0.jar;target/lib/* -DapplicationPropertiesDir=../properties-directory/ com.mygroup.myproject.module2.Main

JMX parameters can be added to make remote monitoring possible. See section 2.C for details.

java -cp .;target/myproject-assembly-1.0.jar;target/lib/* -DapplicationPropertiesDir=../properties-directory/ -Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.port=3309 -Djava.rmi.server.hostname=HOST_IP com.mygroup.myproject.module2.Main


Download whole project from this link.

Comments

Popular posts from this blog

Obfuscating Spring Boot Projects Using Maven Proguard Plugin

Introduction Obfuscation is the act of reorganizing bytecode such that it becomes hard to decompile. Many developers rely on obfuscation to save their sensitive code from undesired eyes. Publishing jars without obfuscation may hinder competitiveness because rivals may take advantage of easily decompilable nature of java binaries. Objective Spring Boot applications make use of public interfaces, annotations which makes applications harder to obfuscate. Additionally, maven Spring Boot plugin creates a fat jar which contains all dependent jars. It is not viable to obfuscate the whole fat jar. Thus obfuscating Spring Boot applications is different than obfuscating regular java applications and requires a suitable strategy. Audience Those who use Spring Boot and Maven and wish to obfuscate their application using Proguard are the target audience for this article. Sample Application As the sample application, I will use elastic search synch application from my GitHub repository.

Hadoop Installation Document - Standalone Mode

This document shows my experience on following apache document titled “Hadoop:Setting up a Single Node Cluster”[1] which is for Hadoop version 3.0.0-Alpha2 [2]. A. Prepare the guest environment Install VirtualBox. Create a virtual 64 bit Linux machine. Name it “ubuntul_hadoop_master”. Give it 500MB memory. Create a VMDK disc which is dynamically allocated up to 30GB. In network settings in first tab you should see Adapter 1 enabled and attached to “NAT”. In second table enable adapter 2 and attach to “Host Only Adaptor”. First adapter is required for internet connection. Second one is required for letting outside connect to a guest service. In storage settings, attach a Linux iso file to IDE channel. Use any distribution you like. Because of small installation size, I choose minimal Ubuntu iso [1]. In package selection menu, I only left standard packages selected.  Login to system.  Setup JDK. $ sudo apt-get install openjdk-8-jdk Install ssh and pdsh, if not already i

Java: Cost of Volatile Variables

Introduction Use of volatile variables is common among Java developers as a way of implicit synchronization. JIT compilers may reorder program execution to increase performance. Java memory model[1] constraints reordering of volatile variables. Thus volatile variable access should has a cost which is different than a non-volatile variable access. This article will not discuss technical details on use of volatile variables. Performance impact of volatile variables is explored by using a test application. Objective Exploring volatile variable costs and comparing with alternative approaches. Audience This article is written for developers who seek to have a view about cost of volatile variables. Test Configuration Test application runs read and write actions on java variables. A non volatile primitive integer, a volatile primitive integer and an AtomicInteger is tested. Non-volatile primitive integer access is controlled with ReentrantLock and ReentrantReadWriteLock  to compa