Wednesday, June 27, 2012

Maven Build Number Plugin - Sample Usage

Suppose we need to add a build number to some artifact (jar, war, etc.). Here I'd like to demonstrate the usage of buildnumber-maven-plugin.

This post is based on:

We have some project and need to include into jar manifest file sequential build number which isn't based on VCS (SVN, Git, Mercurial, etc.) revision number. Let's create appropriate pom.xml file and implement small demo to verify the result.

Generate maven project
$ mvn archetype:generate -DgroupId=org.halyph -DartifactId=buildNoTest\
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false

Create the pom.xml

 4.0.0
 org.halyph
 buildNoTest
 jar
 1.0-SNAPSHOT
 buildNoTest
 http://maven.apache.org

 
  
   junit
   junit
   3.8.1
   test
  
 

 
  UTF-8
 

 <!-- 
 If you have access to scm then you can place actual url's. 
 Otherwise with <revisionOnScmFailure /> you can give some fake URLs as follows. 
 -->
 
  scm:svn:http://none
  scm:svn:https://none
  scm:svn:https://none
 

 
  
   
    src/main/resources
   
   
    src/main/filtered-resources
    true
   
  
  
   
    org.codehaus.mojo
    buildnumber-maven-plugin
    1.1
    
     
      generate-resources
      
       create
      
     
    
    
     <!-- 
      doCheck and doUpdate actually talk to repository if it's true,
      Check would check that there are no local changes. 
      Update would update it 
     -->
     false
     false
     <!-- 
      This ensures that even if we are not connected to scm than also
      take the version from local .svn file 
     -->
     
     
     <!--
      Generate sequence build number based on:
      build number and timestamp      
     -->
     Build: #{0} ({1,date})
     
      buildNumber\d*
      timestamp
     
    
   
   
    org.apache.maven.plugins
    maven-jar-plugin
    2.1
    
     
      <!-- will put the entries into META-INF/MANIFEST.MF file -->
      
       ${project.version}
       ${buildNumber}
      
     
    
   
  
 



Create demo application to verify the results
package org.halyph;

import java.io.IOException;
import java.util.ResourceBundle;
import java.util.jar.Attributes;
import java.util.jar.Manifest;

public class App
{
    public static void main( String[] args ) throws IOException
    {
        System.out.println("Verify Resource bundle" );
  
 // Check filtered resources based on generated build number
        ResourceBundle bundle = ResourceBundle.getBundle( "build" );
        String msg = bundle.getString( "build.message" );
        System.out.println(msg);

        System.out.println("\nVerify Generated MANIFEST.MF Properties" );

 // Check Manifest file based on generated build number
        Manifest mf = new Manifest();
        mf.read(Thread.currentThread().getContextClassLoader().getResourceAsStream("META-INF/MANIFEST.MF"));

        Attributes atts = mf.getMainAttributes();

        System.out.println("Implementation-Versio: " + atts.getValue("Implementation-Version"));
        System.out.println("Implementation-Build: " + atts.getValue("Implementation-Build"));
    }
}

Build application several time and Run
$ mvn install 
$ mvn install 
$ mvn install  
$ java -cp target\buildNoTest-1.0-SNAPSHOT.jar org.halyph.App
Verify Resource bundle
Build: #3 (Jun 27, 2012)

Verify Generated MANIFEST.MF Properties
Implementation-Versio: 1.0-SNAPSHOT
Implementation-Build: Build: #3 (Jun 27, 2012)

Summary
  1. We should inform buildnumber-maven-plugin that we won't use version control revision as build number via adding fake <scm> section into pom.xml and <revisionOnScmFailure /> into buildnumber-maven-plugin <configuration>
  2. Implemented custom build number format, see buildnumber-maven-plugin <configuration>/<format> and <configuration>/<items>.
  3. Added build number into jar manifest, see maven-jar-plugin pom.xml section
  4. Tested if generated build number can be properly added in filtered resources
    • created src\main\filtered-resources\build.properties file
    • build.message=${buildNumber}
      
    • added resource filtering, see section <resource> flag <filtering>true</filtering>
  5. Demo application verifying the filtered resources and build number in jar manifest file
 You can git clone this project github

Monday, June 25, 2012

How to Create Session Factory in Hibernate 4

You've probably noticed that org.hibernate.cfg.Configuration.buildSessionFactory is deprecated in Hibernate4, check out Javadocs:

/**
 * Create a {@link SessionFactory} using the properties and mappings in this configuration. The
 * {@link SessionFactory} will be immutable, so changes made to {@code this} {@link Configuration} after
 * building the {@link SessionFactory} will not affect it.
 *
 * @return The build {@link SessionFactory}
 *
 * @throws HibernateException usually indicates an invalid configuration or invalid mapping information
 *
 * @deprecated Use {@link #buildSessionFactory(ServiceRegistry)} instead
 */
public SessionFactory buildSessionFactory() throws HibernateException 

E.g. We have the next old-fashion Hibernate3 code snippets:
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();

Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(new Event("Our very first event!", new Date()));
session.save(new Event("A follow up event", new Date()));
session.getTransaction().commit();
session.close();

Based on Javadocs above we have to apply the next small changes to support new Hibernate 4 buildSessionFactory(ServiceRegistry):
Configuration configuration = new Configuration();
configuration.configure();
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);

Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(new Event("Our very first event!", new Date()));
session.save(new Event("A follow up event", new Date()));
session.getTransaction().commit();
session.close();
You can clone code sample from https://github.com/halyph/tutorials/tree/master/hibernate4-session-factory-sample

Tuesday, June 12, 2012

How to improve cmd.exe prompt

I'm sure that you have some trouble with "too long command prompt in windows cmd.exe" and it is annoying:

Fortunately, it can be easily fixed with PROMPT command (see official help):

> prompt /?

PROMPT [text]

  text    Specifies a new command prompt.

Prompt can be made up of normal characters 
and the following special codes:

  $A   & (Ampersand)
  $B   | (pipe)
  $C   ( (Left parenthesis)
  $D   Current date
  $E   Escape code (ASCII code 27)
  $F   ) (Right parenthesis)
  $G   > (greater-than sign)
  $H   Backspace (erases previous character)
  $L   < (less-than sign)
  $N   Current drive
  $P   Current drive and path
  $Q   = (equal sign)
  $S     (space)
  $T   Current time
  $V   Windows version number
  $_   Carriage return and linefeed
  $$   $ (dollar sign)

I've configured PROMPT User variable to apply my custom PROMPT setting: [$P]$_$$$S
Now the previous console screen looks like this:
As you can see the full current path is shown one line before the input line. Now, we have a plenty of place for typing what ever we need ;-)

Monday, June 11, 2012

Maven Resource Filtering

This post is inspired by:
I assume that reader has a basic understanding of Maven resources.

Simple resource filtering

Let's generate the project:
$ mvn archetype:generate -DgroupId=org.halyph -DartifactId=proptest -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false


  4.0.0
  org.halyph
  proptest
  jar
  1.0-SNAPSHOT
  proptest
  http://maven.apache.org
  
    
      junit
      junit
      3.8.1
      test
    
   

Now, we have an application property file with bunch of properties which must be filtered \proptest\src\main\resources\application.properties:
application.username=${jdbc.username}
application.password=${jdbc.password}
application.databaseName=${jdbc.databaseName}
We have to add build/resources and properties section into pom.xml:

4.0.0
org.halyph
proptest
jar
1.0-SNAPSHOT
proptest
http://maven.apache.org


  junit
  junit
  3.8.1
  test


  
 
    
      
        src/main/resources
        true
      
    

  

    default_username
    default_password
    default_databaseName
  



Lets run maven resource filtering and check the resulted \proptest\target/classes/application.properties file:

$ mvn process-resources
$ cat target/classes/application.properties

application.username=default_username
application.password=default_password
application.databaseName=default_databaseName
As you can see property values were successfully substituted.

 

Resource filtering with external properties file

We can extract Maven properties in external property file \proptest_extfile\src\main\filters\mysql_filters.properties:
jdbc.username=mysql_username
jdbc.password=mysql_password
jdbc.databaseName=mysql_databaseName
also, we have to adjust pom.xml to work properly with external filters (added build/filters and removed properties):

4.0.0
org.halyph
proptest
jar
1.0-SNAPSHOT
proptest
http://maven.apache.org


  junit
  junit
  3.8.1
  test


  

    
        src/main/filters/mysql_filters.properties
    
    
      
        src/main/resources
        true
      
    



Let's check the resulted \proptest\target\classes\application.properties file:
$ mvn process-resources
$ cat target/classes/application.properties

application.username=mysql_username
application.password=mysql_password
application.databaseName=mysql_databaseName

 

Mixed resource filtering with external/internal properties 

What happen if we have overlapped properties in pom.xml with external property file.
Modified pom.xml:

4.0.0
org.halyph
proptest
jar
1.0-SNAPSHOT
proptest
http://maven.apache.org


  junit
  junit
  3.8.1
  test


  

    
        src/main/filters/mysql_filters.properties
    
    
      
        src/main/resources
        true
      
    


     
 default_databaseName



Now, check the resulted \proptest\target\classes\application.properties file:
$ mvn process-resources
$ cat target/classes/application.properties

application.username=mysql_username
application.password=mysql_password
application.databaseName=default_databaseName
In this case Maven uses application.databaseName property from pom.xml

Managing properties with properties-maven-plugin 

Please check the plugin home page for more details http://mojo.codehaus.org/properties-maven-plugin

This plugin read external property and they behave like were declared in pom.xml.
Modified pom.xml:

4.0.0
org.halyph
proptest
jar
1.0-SNAPSHOT
proptest
http://maven.apache.org


  junit
  junit
  3.8.1
  test


  

    
        
            org.codehaus.mojo
            properties-maven-plugin
            1.0-alpha-2
            
                
                    initialize
                    
                        read-project-properties
                    
                    
                        
                            src/main/filters/cust_mysql_filters.properties
                        
                    
                
            
        
    
    
    
        src/main/filters/mysql_filters.properties
    
    
    
      
        src/main/resources
        true
      
    



Also, we have to add new external property file just to verify the property overlapping issue:
\proptest_extfile\src\main\filters\cust_mysql_filters.properties:
jdbc.username=cust_mysql_username
jdbc.password=cust_mysql_password
jdbc.databaseName=cust_mysql_databaseName
Now, it's time to check the resulted file \proptest\target\classes\application.properties file:
$ mvn process-resources
$ cat target/classes/application.properties

application.username=cust_mysql_username
application.password=cust_mysql_password
application.databaseName=cust_mysql_databaseName

Have you noticed that we've got properties values from cust_mysql_filters.properties and Maven hasn't applied properties from mysql_filters.properties file?

So, as you can see we have several ways for managing/filtering properties with Maven. And, it's very convenient.

You can checkout code snippets from github

First steps in Maven

Here I'm going to collect the most important resources which helps quickly use Maven in the "right" way.

Intro Tutorials

  1. Java Brains: Maven - 10 video tutorials cover very basic Maven use cases. 
  2. Maven By Example - free e-book which step-by-step how the Maven "world." I've notices that off-line PDF book is a little bit outdated (i.e. some POM samples)
  3. Maven Getting Started Guide - guide from Apache Maven Project
I must say that item 1 is optional, but item 2 is mandatory for newcomers.

Tutorial, How-tos and FAQs

  1. Mkyong.com Maven Tutorial - short and descriptive Q&A tutorials.
  2. AVAJAVA - Maven Tutorials - very huge collection of how-to's and Q&A, there are about 80+ articles. 

Cheat Sheets

  1. Dzone Maven 2
  2. http://cheat.errtheblog.com/s/maven/
  3. http://blog.cliffano.com/2006/07/27/my-maven2-cheat-sheet/


Newcomers should clarify for yourself the next maven items which can potentially boost their productivity in future:
  1. Maven lifecycles
  2. Multi-module project
  3. Resource filtering
  4. Maven Profiles