Showing posts with label maven. Show all posts
Showing posts with label maven. Show all posts

Maven custom packaging with the assembly plugin

It's not uncommon to need a custom packaging or assembly for a given project for some reason or another, this can be accomplished in a certain number of ways

Recently I needed an application to be packaged as the following structure :

|- runnable-jar.jar
|- lib
    |-- axis.jar
    |-- commons.logging.jar 
|- certificates
   |-- cacerts.jks
|- config
   |-- config.properties
|- logs
   

The schema is pretty self-explanatory I needed a runnable JAR at the root of my dist folder with a few other folders such as config, logs, etc.

One way to accomplish this with maven is to use maven-assembly-plugin

The Assembly Plugin for Maven is primarily intended to allow users to aggregate the project output along with its dependencies, modules, site documentation, and other files into a single distributable archive.

Your project can build distribution assemblies easily, using one of the convenient, prefabricated assembly descriptors.

These descriptors handle many common operations, such as packaging a project's artifact along with generated documentation into a single ZIP archive. Alternatively, your project can provide its own descriptor and assume a much higher level of control over how dependencies, modules, file-sets, and individual files are packaged in the assembly.

Currently the plugin can create distributions in the following formats:

  • zip
  • tar
  • tar.gz
  • tar.bz2
  • jar
  • dir
  • war
  • format that the ArchiveManager has been configured

For this tutorial we will be using the dir format in order to output the project structure described above

Let's start with the easy part first, the maven assembly plugin configuration where we will tell the plugin where to find our assembly file and where to output the result of the assembly operation


    
...

    
        
            
                maven-assembly-plugin
                
                    false
                    
                        
                        src/main/resources/assembly.xml
                    
                    
                    ${project.build.directory}/dist/
                
            

            
                maven-resources-plugin
                
                    UTF-8
                
            
            
                maven-compiler-plugin
                
                    ${java.version}
                    ${java.version}
                    ${project.build.sourceEncoding}
                
            
        
    
...


Now since in our case we want all the files in the resource directory to be handled by the assembly plugin we will configure the maven resources plugin to ignore everything inside the resources folder (please note that this is an optional step and it might not apply to your project)


...  

    
       
          ${basedir}/src/main/resources
          
              **/**
           
        
     

...

Once the maven part is done we can get started with the core code

If you remember we will end up with a runnable JAR file so go ahead and create a Main class like so :


package com.ufasoli.maven.custom.assembly;

/**
 * User: Ulises Fasoli
 * Date: 23.06.2014
 * Time: 18:03
 * Project : maven-custom-assembly
 */
public class Main {

    public static void main(String[] args) {
        System.out.println("HELLO WORLD !");
    }
}

Since this is going to be a runnable JAR file we will need to configure the maven JAR plugin to generate the manifest file with our main class




   org.apache.maven.plugins
   maven-jar-plugin
   2.4
   
      
         
            com.ufasoli.maven.custom.assembly.Main
            lib/
            true
         
       
   

Now we get to the core of the subject, the assembly file :


    paynet-dir
    
        dir
    
    false
    
        
        
            /lib
            
                ${project.groupId}:${project.artifactId}
            

        
             
            
                /
                
                    ${project.groupId}:${project.artifactId}
                
            

    

    
        
            src/main/resources/keystore/Certificate.SSL
            /certificates
        
        
            src/main/resources/config
            /config
        

        
            src/main/resources/config
            /logs
            
                *
            
            false
        

        
            src/main/resources/docs
            /docs
            
                *
            
        
    

Now this file is pretty self-explanatory but below are the highlights :

  • format --> the output format for our assembly (directory in our case)
  • dependencySets--> which artifacts to include in the final structure and where to put them
  • fileSets--> which files to include in the final structure and where to put them

Now you can build your assembly by running the following maven goal :

    mvn clean package assembly:single

Once the goal completed under the /target folder you should find your custom project structure

As usual you can find the code source for this tutorial over at my github account here

Asciidoctor maven integration : introduction to asciidoctor and maven asciidoctor plugin part 2/2

This is the second part of the Asciidoctor maven integration tutorial part 1/2 where we explore some of Asciidoctor cool features

4. Additional cool formatting elements and content

There are plenty of nice cheat-sheets out there that resume much better all the cool stuff you can do with (see 5. Some useful links) so I will just list here a few tips to get you started

4a. Asciidoc files inclusion or composition

Personally when writing documentation I like to create a separate file for each topic and then include them in an a big index file (you can do this otherwise if you prefer) this can easily be done using the include macro

Let's create a new Asciidoc page named topic1 and add some content to it

= Topic 1

== Intro

This page describes some information related to topic1

and now include the newly created page using the include macro

= Asciidoctor hello world



include::topic1.ad[]

After re-compiling the code you should end up with the content of the file topic1.ad inside the index.html file

4b. Table of contents (TOC)

Asciidoctor has a lot of macros and attributes that help you when writing documentation, the full list of attributes can be found here

Attributes are configured as child tags of the attributes XML tag under the maven asciidoctor plugin. To enable the table of contents while providing a TOC level we will use the toclevels attribute, since once you start writing a lot of documentation you could end up with a pretty big HTML document it's a good idea to enable the creation of anchors using the setanchors attribute



  
     
          org.asciidoctor
          asciidoctor-maven-plugin
          ${version.asciidoctor}
          
              
                 output-html
                 generate-resources
                 
                     process-asciidoc
                 
                 
                     html
                     book                    
                     
                          
                          true
                          
                          3
                     
                 

               
           
      
  


Once you configured the maven plugin it's time to add the :toc: attribute to the index.ad header

Please be aware within the the first lines of a document known as document header spacing and markup are important as they have special meaning and are handled differently by the asciidoc parsing engine

, for more information on the document header please check the documentation here

= Asciidoctor hello world
:toc:


include::topic1.ad[]

Once the documentation files generated the result should be pretty close to the one in the picture below :

Please note : Not all attributes are supported through the maven asciidoctor plugin so you have to play a bit with the maven configuration to see which ones are supported.
4c. Adding images in your documentation

Everyone knows a picture is worth 1000 words so why don't add some pretty pictures to your documentation

By default when generating the documentation files containing images the asciidoctor plugin will prefix all image paths with images/ this of course can be changed but I usually leave it with the default option

We will now add an images folder to our maven project under src/main/resources/images and put an image of your choice inside of it in my case asciidoc-logo.png

Once this is done let's add our image to our document

= Topic 1

== Intro

This page describes some information related to topic1.

Asciidoc is cool

image::asciidoc-logo.png[Asciidoc logo]

Now we have included an image in our doc file but we're not done yet, you need to instruct maven to copy our images folder to the generated-docs target folder

 
...
        
            
                
                src/main/resources/images
                ${build.directory}/generated-docs/images
            
  .....


4d. Code syntax highlighting

Code syntax highlighting is very important when writing documentation since it helps with the readability. Asciidoc currently supports 4 frameworks to handle your code highlighting

  • coderay
  • prettify
  • highlightjs
  • pygments (not currently supported by maven asciidoctor plugin)

For this tutorial let's say we will use coderay so we first need to activate the syntax highlighting in the maven POM file :



  
      
          org.asciidoctor
          asciidoctor-maven-plugin
          ${version.asciidoctor}
          
             
                 output-html
                 generate-resources
                 
                    process-asciidoc
                 
                 
                      
                      coderay
                      html
                      book

                      
                         
                         true
                         3
                     

                 
              
          
       
    
  

Once our maven configuration is done we can add some source code to our docs, the syntax is pretty straightforward in it's most basic form you just put [source, language] and you surround your code with ---- like so :

[source,java]
----
public class HelloWorld{

   public static void main(String[] args){
      System.out.println("Hello World");
   }
}
----

Once your docs file regenerated you should see something like this :

4e. External links (target _blank)

Whenever I'm reading an HTML documentation containing a link I prefer it when the link opens automatically in a new tab i.e.target="_blank"

This can be achieved using link attributes however by default in Asciidoc this feature is disabled; luckily you just need one small line in your pom.xml file to enable this feature with an attribute


  
      
          org.asciidoctor
          asciidoctor-maven-plugin
          ${version.asciidoctor}
          
             
                 output-html
                 generate-resources
                 
                    process-asciidoc
                 
                 
                      
                      coderay
                      html
                      book

                      
                         
                         true
                         3
                         
                        true
                     

                 
              
          
       
    
  

Now you can go ahead an add your links withe


http://powerman.name/doc/asciidoc[Asciidoc cheatsheet, window="_blank"]


So this concludes this 2 part introductory tutorial to Asciidoctor and maven integration ; have fun writing cool documentation!

5. Some useful links

As usual you can find the code source for this tutorial over github here

Below is a list of useful links to help you with Asciidoctor such as cheatsheet or general documentation :

Asciidoctor maven integration : introduction to asciidoctor and integration with maven asciidoctor plugin part 1/2

For some time now I have been hearing a lot aboutAsciiDoc as a mean to write documentation but never had the chance to use it...

Recently I stumbled upon AsciiDoctor and since I was about to begin working on a small project with no previous documentation I thought it was the perfect time to try it out..

Documentation is an important part of a project which more often than we would like gets put aside for a great number of reasons. One of them is that we as developpers tend not to like writing documentation...

0.Intro and scope

In this tutorial I will show you how to integrate Asciidoctor class in your Java project and get you started with a small documentation example as well as some tips such as :

  • Asciidoc templating using fragments
  • Generating a TOC (table of contents) for your documentation
  • Integrating images in your asciidoc files
  • Code syntax highlighting in your asciidoc files
  • Making external links (i.e. _target blank)

Please note that I assume you have some knowledge of Asciidoc so I won't delve into much detail regarding Asciidoc

1. What is AsciiDoc ?

AsciiDoc is a text document format for writing notes, documentation, articles, books, ebooks, slideshows, web pages, man pages and blogs. AsciiDoc files can be translated to many formats including HTML, PDF, EPUB, man page. AsciiDoc is highly configurable: both the AsciiDoc source file syntax and the backend output markups (which can be almost any type of SGML/XML markup) can be customized and extended by the user.

2. What is Asciidoctor ?

Asciidoctor is a pure Ruby processor for converting AsciiDoc source files and strings into HTML 5, DocBook 4.5 and other formats. It’s published as a RubyGem and is available under the MIT open source license.

I invite you to take a look to this nice presentation by Dan Allen Discover Zen Writing with Asciidoc which gives you a good overview of AsciiDoc

3. First steps and configuration

First things first go ahead and create a simple maven module let's say a simple JAR for example using the maven archetype plugin or using you favorite IDE

mvn archetype:generate -DgroupId=com.ufasoli -DartifactId=asciidoc-helloworld -DinteractiveMode=false

Once your maven project is created go ahead and create a folder named asciidoc under src/main this is where we will be putting our Asciidoc files

Let's go ahead and create our first asciidoc file under the folder we just created let's name it index.ad and for the moment keep it simple let's just add the page title

= Asciidoctor hello world

So now with our first asciidoc file let's go ahead and configure maven to parse our documentation files and generate HTML documentation files by using the Maven Asciidoctor plugin




  
     
          org.asciidoctor
          asciidoctor-maven-plugin
          ${version.asciidoctor}
          
              
                 output-html
                 generate-resources
                 
                     process-asciidoc
                 
                 
                     html
                     book                    
                 
               
           
      
  

Now if you run a mvn clean compile you will see an index.html that will be generated under the target/generated-docs folder with an output similar to :

So that's it for the first part of this tutorial, you can find the rest tomorrow on part 2

Running a spring boot application with maven

On the last 2 part tutorial that I published recently on Spring boot :Spring boot and spring data (part 1) and Spring boot and spring data (part 2) I said that when using pure maven (not the groovy approach) you needed to either package the project and then run the JAR manually or use the maven mojo exec plugin (which I preferred)

But as often after playing a bit more with it I realized that there is an even simpler solution and that is using the run goal of the spring-boot maven plugin

So you can simply run your spring-boot project by executing the following goal on your console/IDE


 mvn spring-boot:run

Spring boot and spring data jpa tutorial - A sample application using spring 4.0 spring boot and JPA (part 2/2)

This is the second part of the Spring boot and spring data jpa tutorial - A sample application using spring 4.0 spring boot and JPA

At the end of the tutorial I promised you that we will be removing one of the steps when running the application, that is merge the package and run in a maven command and make him do the work

5.- Making maven run the JAR directly

We're going to make maven run the runnable JAR for us after it has been packaged, for this purpose we're going to use one of org.codehaus.mojo maven plugins



....

        
            
                org.springframework.boot
                spring-boot-maven-plugin
            

            
                org.codehaus.mojo
                exec-maven-plugin
                1.2.1
                
                    com.ufasoli.tutorials.spring.boot.HelloWorldApp
                
            
        
    
...

So what's happening here ? :

  • By adding the exec plugin to the build section of our pom.xml and providing a mainClass when we run the appropriate maven goals the application will be packaged and run directly from maven

You can try this by running :

    mvn clean package exec:java

By running this on your console the application will be packaged and run directly using maven

Now let's add some more interesting stuff to our app

6.- Adding Spring Data and JPA support

We're now going to add some Spring Data and JPA support to our app.

The first thing you need to do is add the additional spring boot starter module (spring-boot-starter-data-jpa) to your maven dependencies and since we will be using an embedded HSQL database the dependency for the HSQL driver too:

 
 ...
        
        
            org.springframework.boot
            spring-boot-starter-data-jpa
        

         
            hsqldb
            hsqldb
            ${version.hsqldb}
        
...


The next thing you need to do is tell spring to enable Spring Data and its repository features this is done by simply adding the @EnableJpaRepositories to your Spring App class

@ComponentScan 
@EnableAutoConfiguration
@EnableJpaRepositories
public class HelloWorldApp {

    public static void main(String[] args) throws Exception {

        SpringApplication.run(HelloWorldApp.class, args);

    }
}

And that's it if you now build and run your application you will have a Spring web application with Spring Data and JPA support even though the app won't do much for the moment ;).

So what's happening here?

  • Annotating the Spring Application class with the @EnableJpaRepositories will cause a lot of "magic" to happen and a lot of things will be configured/initialized for you such as an Entity Manager, DataSource (see next item), JPA Vendor adapter ..
  • Since we haven't defined a DataSource if Spring finds an in memory JDBC driver in the Classpath it will automatically create one for us using a set of predefined conventions

Now let's add some logic to our app :

7.- Adding some Spring data and JPA logic

The first thing we're going to be doing is adding a simple JPA entity to perform some CRUD operations later on



import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Book {


    @Id
    protected String isbn;
    protected String title;
    protected String author;
    protected String description;
    // omitting setters/getters/constructors
}

So now that we have our entity lets use one of the great features of Spring Data : The Repositories Abstraction :

The goal of Spring Data repository abstraction is to significantly reduce the amount of boilerplate code required to implement data access layers for various persistence stores.

By annotating an interface with @Repository and making this interface extend CrudRepositoryYou will get among other things 2 pretty nifty goodies of the box:

  • Some utility CRUD methods such as findAll() or count()
  • Auto-implementation of methods based on naming convention such as findBooksByAuthor()

And the best part is you get all of this without writing any code logic for these methods (of course you can override these methods, and write some custom methods) as shown in the doc, you can even avoid yet to write some code by using for example the @Query annotation

So now lets create our CRUD repository for our entity with a custom method to find the books by their author


import com.ufasoli.tutorials.spring.boot.model.Book;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;


@Repository
public interface BookRepository extends CrudRepository {

    public Iterable findBooksByAuthor(@Param("author") String author);
}

This interface will be picked up by Spring an instantiated accordingly.

We're almost done with our JPA/database logic, one last thing I would like to do is to have some data inserted automatically into the database when the application starts (especially since we're dealing with an in-memory database

Once again we can take advantage of another Spring convention, if you place a data.sql file in your maven resources directory the script will be automatically executed when the database will be bootstrapped and after reverse engineering your entities into the database

INSERT INTO book(isbn, title, author,description) VALUES ('1111111', 'The Spirit Thief (The Legend of Eli Monpress #1)', 'Rachel Aaron',
                         'Eli Monpress is talented. He''s charming. And he''s a thief.But not just any thief. He''s the greatest thief of the age - and he''s also a wizard. And with the help of his partners - a swordsman with the most powerful magic sword in the world but no magical ability of his own, and a demonseed who can step through shadows and punch through walls - he''s going to put his plan into effect.The first step is to increase the size of the bounty on his head, so he''ll need to steal some big things. But he''ll start small for now. He''ll just steal something that no one will miss - at least for a while. Like a king');

INSERT INTO book(isbn, title, author,description) VALUES ('2222222', 'The Spirit Rebellion (The Legend of Eli Monpress, #2)', 'Rachel Aaron',
                         'Eli Monpress is brilliant. He''s incorrigible. And he''s a thief.He''s also still at large, which drives Miranda Lyonette crazy. While she''s been kicked out of the Spirit Court, Eli''s had plenty of time to plan his next adventure. But now the tables have turned, because Miranda has a new job -- and an opportunity to capture a certain thief. Things are about to get exciting for Eli. He''s picked a winner for his newest heist. His target: the Duke of Gaol''s famous ''thief-proof'' citadel. Eli knows Gaol is a trap, but what''s life without challenges? Except the Duke is one of the wealthiest men in the world, a wizard who rules his duchy with an iron fist, and an obsessive perfectionist with only one hobby: Eli. It seems that everyone is hunting for Eli Monpress');

INSERT INTO book(isbn, title, author,description) VALUES ('3333333', 'The Spirit Eater (The Legend of Eli Monpress, #3)', 'Rachel Aaron',
                         'With the pressure on after his success in Gaol, Eli Monpress, professional thief and degenerate, decides it''s time to lie low for a bit. Taking up residence in a tiny seaside village, Eli and his companions seize the chance for some fun and relaxation. Nico, however, is finding it a bit hard. Plagued by a demon''s voice in her head and feeling powerless, she only sees herself as a burden. Everyone''s holiday comes to an untimely close, though, when Pele arrives to beg Eli''s help for finding her missing father. But there are larger plans afoot than even Eli can see, and the real danger, and the solution, may lie with one of his own and her forgotten past. If only Nico could remember whose side she''s on.');

INSERT INTO book(isbn, title, author,description) VALUES ('4444444', 'The Spirit War (The Legend of Eli Monpress, #4)', 'Rachel Aaron',
                         'Eli Monpress is vain. He''s cocky. And he''s a thief. But he''s a thief who has just seen his bounty topped and he''s not happy about it. The bounty topper, as it turns out, is his best friend, bodyguard, and master swordsman, Josef. Who has been keeping secrets from Eli. Apparently, he''s the only prince of a rather feisty country and his mother (a formidable queen who''s every bit as driven and stubborn as he is) wants him to come home and do his duty, which means throwing over personal ambitions like proving he''s the greatest swordsman who ever lived. Family drama aside, Eli and Josef have their hands full. The Spirit Court has been usurped by the Council of Thrones and someone calling herself the Immortal Empress is staging a massive invasion. But it''s not just politics --- the Immortal Empress has a specific target in mind: Eli Monpress, the greatest thief in the world.');

INSERT INTO book(isbn, title, author,description) VALUES ('5555555', 'Spirit''s End (The Legend of Eli Monpress #5)', 'Rachel Aaron',
                         'First rule of thievery: don''t be a hero. When Eli broke the rules and saved the Council Kingdoms, he thought he knew the price, but resuming his place as the Shepherdess''s favorite isn''t as simple as bowing his head. Now that she has her darling back, Benehime is setting in motion a plan that could destroy everything she was created to protect, and even Eli''s charm might not be enough to stop her. But Eli Monpress always has a plan, and with disaster rapidly approaching, he''s pulling in every favor he can think of to make it work, including the grudging help of the Spirit Court''s new Rector, Miranda Lyonette. But with the world in panic, the demon stirring, and the Lord of Storms back on the hunt, it''s going to take more than luck and charm to pull Eli through this time. He''s going to have to break a few more rules and work with some old enemies if he''s going to survive');

8.- Wrapping things up with a REST controller

To wrap things up we'll add a simple RestController that will interact with our freshly created Repository


import com.ufasoli.tutorials.spring.boot.model.Book;
import com.ufasoli.tutorials.spring.boot.repositories.BookRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController // assumes @ResponseBody annotation in methods annotated with  @RequestMapping
@RequestMapping(value = "/books", produces = MediaType.APPLICATION_JSON_VALUE)
public class BookController {

    @Autowired
    protected BookRepository bookRepository;

    @RequestMapping
    public Iterable books() {
        return bookRepository.findAll(); // uses the findAll() method inherited from CrudRepository
    }


    @RequestMapping(value = "/{isbn}")
    public Book book(@PathVariable("isbn") String isbn) {
        return bookRepository.findOne(isbn);// uses the findOne() method inherited from CrudRepository
    }


    @RequestMapping(value = "/{isbn}", method = RequestMethod.DELETE)
    public String deleteBook(@PathVariable("isbn") String isbn) {

        try {
            bookRepository.delete(isbn);
            return String.format("Book [%s] successfully deleted", isbn);// uses the delete() method inherited from CrudRepository
        } catch (Exception e) {
            return String.format("A problem occurred when deleting Book [%s]", e.getMessage());
        }
    }

    @RequestMapping("/author/{author}")
    public Iterable booksByAuthor(@PathVariable("author") String author) {

        return bookRepository.findBooksByAuthor(author);// uses the custom method defined in our BookRepository interface
    }


}

So that's it you can re-run your application now using the maven goal

     mvn clean package exec:java

You should see your application bootstrapping your database and inserting data, and once it's fully started you should be able to play with your Web Service

9.-Some final thoughts

I must say that I quite enjoyed playing with Spring boot, as long as you're using the full spring stack it helps you get things running quickly and has some very useful starter modules and conventions

I also added the actuator module which gives you some metrics and stats (as REST endpoints) on your application which is pretty cool to have when running the app in production

Check it out here

As usual you can find the code source for this application over at my github account here

Spring boot and spring data jpa tutorial - A sample application using spring 4.0 spring boot and JPA (part 1/2)

Spring boot is a strongly opinionated framework / generator based on the principle of convention over configuration, which according to the website:

Spring Boot makes it easy to create Spring-powered, production-grade applications and services with absolute minimum fuss. It takes an opinionated view of the Spring platform so that new and existing users can quickly get to the bits they need

Basically by using a few annotations and minimum boilerplate code the framework/generator will configure all the necessary beans and contexts based on a set of conventions.

Spring boot has a few modules that depending on your needs can speed-up development such as :

  • spring data jpa
  • spring data mongodb
  • spring web
  • spring actuator
  • ...

Personally I find that when using the spring stack this tool is pretty awesome!!

When using this tool you must know that there are actually 2 ways to use spring boot :

  1. Using the cli (and by extension groovy)
  2. Using good old maven and the spring-boot plugins

In this tutorial we will be building a simple Hello World tutorial as a RESTful web service

1.- Getting things started

Add the required maven dependencies to your pom.xml

        spring-boot-hello-world-ws
    spring-boot-hello-world-ws
    1.0-SNAPSHOT


    
    
        org.springframework.boot
        spring-boot-starter-parent
        1.0.0.RC1
    

    
    
        
            org.springframework.boot
            spring-boot-starter-web
        

    

    
    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            

        
    

    
    
    
        
            spring-snapshots
            http://repo.spring.io/snapshot
            
                true
            
        
        
            spring-milestones
            http://repo.spring.io/milestone
            
                true
            
        
    
    
        
            spring-snapshots
            http://repo.spring.io/snapshot
        
        
            spring-milestones
            http://repo.spring.io/milestone
        
    

So what's happening here :

  • Since spring-boot is not G.A. yet you will need to include the Spring milestones repositories
  • When using maven your project will have to inherit from the spring boot starter parent in order for it to work
  • We are using the web module (see dependencies)
  • The spring-boot-maven-plugin will build a runnable jar file

2.- Creating our first controller

With the basic configuration out of the way we can start building our app.

Since this is going to be a RESTful API we will create a REST controller. Spring included a new annotation in the latest version @RestController. Types that carry this annotation are treated as controllers where @RequestMapping methods assume @ResponseBody semantics by default; which in our case it's what we want.

So with that being said let's write our first controller :


package com.ufasoli.tutorials.spring.boot.web.controllers;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created with IntelliJ IDEA.
 * User: Ulises Fasoli
 * Date: 04.02.14
 * Time: 15:33
 */
@RestController
@RequestMapping(value = "/hello", produces = MediaType.APPLICATION_JSON_VALUE)
public class HelloWorldController {

    @RequestMapping
    public String sayHello(){
        return "Hello World";
    }
}

Nothing special here just a simple Spring MVC controller but using the new @RestController annotation

We are now 2 steps away from running our Spring app.

3.- Creating our Spring Application main class

In order for the Spring context to be bootstrapped you will need to create a class that will run the Spring application inside a main method and a few annotations.So let's go ahead and do that :

package com.ufasoli.tutorials.spring.boot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;

/**
 * Created with IntelliJ IDEA.
 * User: Ulises Fasoli
 * Date: 04.02.14
 * Time: 11:39
 *
 */
@ComponentScan // spring standard component scan
// spring boot autoconfiguration will bootstrap your Spring
//application while attempting to configure the beans you need
// it will also bootstrap an in-memory database if a driver is found
// in the classpath and no datasource is defined
@EnableAutoConfiguration
public class HelloWorldApp {

    public static void main(String[] args) throws Exception {

        SpringApplication.run(HelloWorldApp.class, args);

    }
}


What's happening here? :

  • The @Component is standard spring annotation to search for annotated beans in the classpath
  • The @EnableAutoConfiguration is spring boot specific and will be doing most of the "magic"

We are now one step away from running our spring application! Yep that's it no web.xml configuration, no XML files, nothing!!

4.- Taking it for a spin

With the application configured it's time to test our app, so fire-up your IDE or your console and execute the following maven goal :

  mvn clean package

Once your app is packaged you can run the generated runnable JAR file by simple going into the target folder and running :


  java -jar .\spring-boot-hello-world-ws-1.0-SNAPSHOT.jar
 

If everything worked as expected you should see the Spring boot / maven output in your console :


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::            (v1.0.0.RC1)

2014-02-04 15:46:47.628  INFO 12516 --- [           main] c.u.tutorials.spring.b
oot.HelloWorldApp  : Starting HelloWorldApp on LTULF01 with PID 12516 (C:\dev\wo
rkspaces\idea\java-blog-tutorials\spring-boot-hello-world-ws\target\spring-boot-
hello-world-ws-1.0-SNAPSHOT.jar started by ULF)
....

That's it you can now test your controller by calling the url :

 curl http://localhost:8080/hello.json

You should see the Hello world message printed out in the console

Personally it kind of bugs me to have to package the app and then run it manually so on part 2 of this tutorial we will change this so Maven will do the work for us.....

Create a runnable war with embedded tomcat or run a maven tomcat war project without maven and a tomcat installation

I know the title of this post is a bit of a contradiction, running a maven tomcat webapp without maven and a tomcat installation WTF?.

So before we begin let me clarify what I mean. You will need maven on your development environment and you will be using the tomcat7 maven plugin to deploy and run your application-.

When delivering a small to medium sized java web application it could be nice to have it as a self contained application allowing you to just drop-it anywhere and just run it without having to install/upgrade Maven, Apache Tomcat, etc. (of course you'll still need java :p )

What I would like to accomplish is to develop a web application using my usual tools and stack and then deliver the application in it's most simple way, without having to install and configure tomcat and maven on the target system.

Running a WAR project without a Tomcat installation is not very complicated you just use the maven tomcat plugin and run the appropriate goal (ex: tomcat7:run).

But running the app on a given system will require to have a local maven installation. Now this can avoid this by writing your own runner using the tomcat API(especially Tomcat Runner cli ) and including the appropriate tomcat JARs in your CLASSPATH.

Luckily, as often, there's an app plugin for that which honestly does pretty much all the job.

I'm talking of the tomcat7 maven plugin which you probably already use in some of your projects.Well as it turns out it has a very useful mojo that allows you to accomplish the task at hand.

The process of generating the runnable WAR is pretty simple (thank you Apache):

1. Add the tomcat plugin to your maven configuration





   com.ufasoli
    runnable-war
    1.0-SNAPSHOT
     war
...
   
     ...

     
        runnable-war
        
            
                
                    org.apache.tomcat.maven
                    tomcat7-maven-plugin
                    2.1
                    
                        
                            tomcat-run
                            
                                exec-war-only
                            
                            package
                            
                                /                               
                                exec-war
                                jar
                            
                        
                    
                

            
            
        
    

Here I'm configuring the generation of the runnable war inside a maven profile. If you do not want to do this just extract the build part of my runnable-war maven profile into your main maven configuration


2. Build your maven project with the optional profiles

Run the maven command in order to build your war and runnable JAR

  mvn clean package -Prunnable-war

This will generate 3 extra files on your target folder (additionally to your packaged war file) :

  • ${yourapp-version-war-exec}.jar : A runnable JAR file that contains the tomcat embedded runtime/li>
  • war.exec.manifest : a manifest file containing the main class to run
  • war-exec.properties : a properties file containing some tomcat config options and info

3. Run your WAR file

Once the project is packaged, you can go inside the target folder and run the following command to start the tomcat server


 java -jar ${yourapp-version-war-exec}.jar

I find this approach pretty useful as you can control your server environment and configuration directly from your app, but of course it's not applicable to all projects.

As usual you can find the code source for this project over at github

Maven build number, versioning your projects builds automatically

By default all maven projects have a version number that you increase upon releases whether it's a minor or major release.

When you are in a scenario in which you continuously deliver application (for example on a staging server) it's probably a good idea to have some unique build identifier so as to know the exact version that is deployed on the server

Luckily the guys over at codehaus have an app plugin just for that .

I'm talking about the buildnumber-maven-plugin

This plugins will generate a build identifier each time you compile your maven project and make this identifier available through a maven variable ${buildNumber}

The plugin can generate build numbers in 3 ways :

  • SCM (my personal favorite)
  • Sequential build number
  • Timestamp

Personally I prefer the SCM approach since it's coupled with your commits, and I will here I will be showing how to do that

First you will have to configure the maven scm plugin with your details, otherwise you'll end up with error messages like :

 Failed to execute goal org.codehaus.mojo:buildnumber-maven-plugin:1.2:create (default) on project simple-webapp: Execution default of goal org.codehaus.mojo:buildnumber-maven-plugin:1.2:create failed: The scm url cannot be null. -> [Help 1]


   
    com.ufasoli.tutorial
    swagger-spring-mvc
    1.0-SNAPSHOT
     
     
           scm:git:https://github.com/ufasoli/spring-mvc-swagger-tutorial.git
           https://github.com/ufasoli/spring-mvc-swagger-tutorial.git
     

 ...

Here I'm using a github repository as SCM

Once your SCM details are set you can configure the build number plugin :


  
   ...
     
         org.codehaus.mojo
         buildnumber-maven-plugin
         1.2
         
           
              validate
              
                create
              
           
         
         
            false
            false
            5
         
      

  

Here I'm configuring the plugin with 3 worth noting options

  • doCheck : Check for locally modified files. If true build will fail if local modifications have not been commited
  • doUpdate : Update the local copy of your repo. If true the plugin will update your local files with the remote modifications before building
  • shortRevisionLength : shortens the git revision to the number of characters specified in the tag (5 in our case)

Once everything is configured you will be able to access the ${buildNumber} variable in your pom (even though your IDE might complain that the variable cannot be resolved don't worry it will be there when you package your project)



${project.artifactId}${project.version}_${buildNumber}



Maven filtering test resources

When running tests in maven it's common usage to have configuration files that should be filtered.

When filtering "normal" resources the syntax is the following :






...

  
    
      
        ${project.basedir}/src/main/resources
        true
      

           
...

Whereas when filtering test resources the syntax is following :





 ...

  
      
          
              ${project.basedir}/src/test/resources
              true
          
      
  ...
  

Otherwise your test resources will not be filtered

Debugging a maven failsaife selenium build in intellij

Recently I had to debug a set of Selenium tests using the failsafe plugin and the embedded tomcat7 plugin using Intellij Idea

Usually you can just click on IDE's the debug button and Intellij will take care to launch the build and attach a debugger to the appropriate debug port:

However this time it wasn't working I had 2 issues with my build :

  1. My breakpoints where completely ignored
  2. The maven build just kept waiting without exiting the project even once the integration tests where finished

So I looked into the possible XML configuration tags for the failsafe plugin and thought that the <debugForkedProcess>true</debugForkedProcess> would be my salvation however I was wrong...

So what's happening here ?

By default, maven runs your tests in a separate ("forked") process. So when you set this property to true, the tests will automatically pause and await a remote debugger on port 5005

However this was not going happen since when you click on the IDE's debug button Intellij will execute a java debugging command similar to this :

java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:63093,suspend=y,server=n -Dmaven.home=C:\dev\bin\maven -Dclassworlds.conf=C:\dev\bin\maven\bin\m2.conf -Dfile.encoding=UTF-8 -classpath "C:\dev\bin\maven\boot\plexus-classworlds-2.4.2.jar;C:\dev\ide\intellij\lib\idea_rt.jar" org.codehaus.classworlds.Launcher --errors --fail-fast --strict-checksums clean verify -P selenium
Connected to the target VM, address: '127.0.0.1:63093', transport: 'socket'

Then the failsafe process will start and pause the tests waiting for a debbuger to attach to the 5005


-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Listening for transport dt_socket at address: 5005

But as mentioned earlier this will not happen, because Intellij is listening on another port

Upon reading the plugin documentation over here I realized that you can change all of these configuration properties. However I kept reading the plugin documentation and found another promising configuration option <forkMode>true</forkMode>

According to the documentation the forkMode is an option to specify the forking mode. Can be "never", "once" or "always". "none" and "pertest" are also accepted for backwards compatibility. "always" forks for each test-class.

Since in our case we need to attach a debugger to a single thread in order to have our debugger to be called when hitting a break-point we will set this option to never

Now hit again the debug button in your IDE and normally Intellij should be summoned when your break-point is reached

Below is a sample maven configuration excerpt with the configuration for the failsafe plugin


...
  
    org.apache.maven.plugins
    maven-failsafe-plugin
    2.9
    
      
         integration-test
            
                integration-test
            
      
      
        verify
        
           verify
        
      
     
     
        never
     

...

as usual the full code for this application can be found over at my github account

the tests get executed when running the following maven goal :

mvn clean verify -Pselenium

a few tips for the road :

  • Remember to use the suffix IT on your selenium test classes (e.g: MyTestIT.java) otherwise you will have to configure the surefire plugin to ignore them
  • If like me you're running your selenium tests in a self contained mode (i.e : starting the application server, deploying the app, running the tests, stopping the server) remember to configure your server to fork to another process, otherwise the server running process will be started in a blocking mode

Glassfish remote redeploy with maven and the mojo exec plugin

So a few days ago I run into a bug that took me almost a whole day to sort out..

I usually use cargo when I want to deploy an app to a running container but today I've spent several hours trying to make my app redeploy on a remote glassfish web profile server while working within my development/integration environment.

Just to give you some context in this environment I needed to continually deploy the same application on the same server but with different versions.

The first time I deployed the application everything will work as expected but subsequent deployments will throw an error telling me that an application already exists for that context root (see message below) :

 Caused by: org.codehaus.cargo.util.CargoException: Deployment has failed: Action failed Deploying application to target server failed; Error occurred during deployment: Application with name myapp-1.4.8 is already registered. Either specify that redeployment must be forced, or redeploy the application. Or if this is a new deployment, pick a different name. Please see server.log for more details.

Now the asadmin utility tool allows forcing a redeployment by using the --force=true option on the command line but it doesn't work if the WAR file name has changed as glassfish supports only one app per context root unless you use it in conjunction with Glassfish application versioning system but more on that later (see here)

I would argue that the "--force" param should deploy the WAR for a given context and overwrite the existing app regardless if you are using the versioning system or not but that's only my point of view

Side note : While doing some research on my problem I stumbled upon a forum post stating that when using the cargo:redeploy goal the --force=true parameter is used, at the moment I cannot find that blog post so I'm sorry..

So now let's get down to business, in this tutorial I will be showing how to use the codehaus maven exec plugin

Below are the steps that you should follow :

0.- Prerequisites

a. Glassfish versionning system naming conventions

Before beginning with this tutorial you must know that in order for it to work you need to use glassfish's versionning system with your applications otherwise it will always fail when trying to deploy an app for a given context but with a different war name (e.g. myapp-1.0.war -> myapp-1.1.war)

You can find more info on the versionning system here and here but basically glassfish will handle multiple versions of your application for a given context but allowing only 1 version of the application to be active at a given moment

For the versioning system to work you need to define a version for your WAR either in the glassfish-web.xml file or with the -name argument

In this tutorial we will be using the latest (the --name) argument

Please note that you need to respect a WAR file naming convention when versioning your applications (the value for the --name parameter), that convention is :

  {applicationName}:{applicationVersion}.war --> myapp:1.0.war
b. Access rights to Glassfish install path

You will also need to install(unzip) a glassfish instance in a place accessible to the the machine that will be executing the maven goal

c. Enabling asadmin secure admin feature

Lastly Glassfish's secure admin feature needs to be enabled in order to be allowed to do remote deploys; otherwise you will get an error message

[exec] HTTP connection failed with code 403, message

You can enable the secure admin feature by running the following command on your prompt (glassfish instance must be running)

  asadmin --host [host] --port [port] enable-secure-admin

Please note that you have to restart the glassfish instance in order for this functionality to be enabled.

1.- Installing a local glassfish instance

Go to the glassfish download website and download and unzip the appropriate glassfish version (ideally the same that the one of the remote server where you are trying to deploy your app) in a directory of your choice : e.g. /var/glassfish

2.- Defining the password file

You will then need to provide the asadmin tool with a password file since it's no longer supported as a command line argument

So go ahead and create a password file (let's name it glassfish.password) in the folder of your chice (e.g. /var/glassfish/). The file should be a properties files containing the following keys with the passwords values corresponding to your environment:

AS_ADMIN_MASTERPASSWORD=myPassword
AS_ADMIN_PASSWORD=myPassword
AS_ADMIN_USERPASSWORD=myPassword

Note: For this example the password will not be encrypted (you should encrypt it in your production environment). You can find more info on securing your master password in the glassfish documentation here here

3.- Configuring the exec plugin

Head up to your pom.xml file fire up your favorite editor and edit the POM file so it looks something like :





...

 /var/glassfish/bin/asadmin
  admin
  /var/glassfish/glassfish.password
  arte-epg-apipreprod.sdv.fr



....


   myapp
   
      
         org.codehaus.mojo
         exec-maven-plugin
         1.2.1
         
            ${glassfish.asadmin.executable}
            
               --user
               ${glassfish.user}
               --passwordfile
               ${glassfish.password.file}
               --host
               ${glassfish.remote.host}
               deploy
               --force=true
               --name=${project.build.finalName}:${project.version}
               --enabled=true
               ${project.build.directory}/${project.build.finalName}.war
            
         
         
            
               
                  exec
               
               verify
            
         
      
...
   


Please ensure that the value of the --name argument respects glassfish's application versioning naming conventions {appName}:{appVersion}.war

 mvn clean verify
Note: Here we are binding the execution of the goal to the verify phase but you can freely change that or use instead one of the plugin's goals directly from the command line.

4.- Sum-up and final thoughts

Firstly let me tell you that this method is probably not the cleanest way to get things done but for the time being, it will suffice... (at least to me :p)

Secondly, this is not a silver bullet, as sometimes I did encounter problems for example : if the database was not up and the application was marked as not enabled in the glassfish server, or the first time that I switched from deploying without glassfish versioning system to using glassfish's versioning system

Finally, I really don't like the fact that I need a local glassfish instance to deploy on a remote server, and I wonder if it's possible to achieve something similar using the glassfish deployment-client as a maven dependency and invoking the java classes inside the dependency or somehow extend the plugin to take into account force redeploys. So if I have some free time in the near future I will explore the possibility of accomplishing the same thing without needing a glassfish installed locally

Maven resource filtering not working on spring configuration xml file

I recently run on a weird problem while running property filtering on tutorial project that I'm writing.

One of my configuration files (spring XML config files) was being partially filtered (only the first 2 variables were properly "filtered" while the rest was left as they were )

Below is my configuration file. Only the first 2 variables where filtered (mongo.host & mongo.port) :




    

         
        
  
    

    
        
        
    


I've tried a few things and realized that if I moved them around then suddenly it would work but I couldn't put my finger on what was causing the problem

So I decided to remove line by line from the bottom up and check if something will fix the problem

As it turns out what was causing the problem was the '@' in my comment right before the repository configuration.

This actually was a maven bug in the maven-resources-plugin but fear not the bug was corrected in the 2.6 version

So if you come up by this behavior check your pom.xml configuration as by default my maven was using the 2.4.1 version and change it in the build section of your POM to use the more recent version




...

...
    
            
                org.apache.maven.plugins
                maven-resources-plugin
                2.6
            
   
...



...

Managing system scoped jars with maven and the addjars plugin

When using some third party dependencies in a maven project you realize that sometimes some of jars are not available in any of the public maven repositories available (e.g. the oracle jdbc driver that is not available for copyright reasons)

When developing a team project and that you are required to use a jar of this type you have mainly 3 options :

1. Using Maven repository repository manager

There are a few maven repository managers out there which allow mainly to mirror distant maven repositories such as maven central, by storing the remote jars locally and making them available inside the company

This is where you can store your companies jars and wars and some other jar not available in the public repositories

I will not go into the details of the different repository managers but there are mainly 3

I never used Archiva but I really like Nexus. There is a nice comparison matrix over here so you can make and educated choice

Anyhow if you or your company have a repository manager you can easily install the required JAR on your repository.

Once the JAR is installed in the repository it will be available to anyone that uses the repository as long as your settings.xml file or pom.xml file are properly configured.

The main advantage if this approach is that once the JAR downloaded and installed in the repository manager it will be available for all the users and future projects

The main inconvenient is the fact that you need to install a repository manager

2. Installing the JAR in the maven local repository

Installing a JAR in the user's maven local repo is quite straightforward

a) Download the JAR to the local machine
b) Install the JAR in the local repository
    mvn install:install-file -Dfile=/data/downloads/ojdbc6.jar -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0.3
c) Declare the JAR as a maven dependency

   

       .....

      
          
              =com.oracle
              ojdbc6
              11.2.0.3
         
     

  

This is the quickest and simplest approach to implement

The major inconvenient is that every new developer will need to install the JAR in their local repository

3. Using the addjars shade plugin and system as dependency scope

Maven allows you to easily defined dependencies with a system scope. But there is a problem with system scoped jars. When packaging the application (WAR, JAR, etc.) the system scoped jars will not be included in the packaged result. Here is where the addjar plugins comes in handy, this plugin allows you to include system scoped jars when packaging the application

Below is a quick example of a simple java web app with system scoped jar (ojdbc6.jar) :

my-app
|-- pom.xml
`-- src
    |-- main
    |   `-- java
    |   `-- webapp
    |-- external
    |   `-- ojdbc6.jar   

As stated before if I run a mvn package on this project I will get a WAR file but the ojdbc6.jar JAR will not be included under WEB-INF/lib

Thankfully the addjars plugins comes to the rescue here this plugin will include your third party jar in your project's classpath when packaging

You can see below a sample configuration for the plugin in the pom.xml file :


   
...

  
      
       com.googlecode.addjars-maven-plugin
       addjars-maven-plugin
       1.0.5
          
             
                
                  add-jars
                
                
                  
                    
                      ${basedir}/external/
                    
                 
              
           
        
      
    
  
...

The main advantage is that once the pom.xml configured with the dependency and the plugin and the JAR committed into the source control the building becomes transparent for the users

The main inconvenient comes from the fact that you will need to commit the JAR file in your source control repository and handle JAR versions manually

It's good to note that the add-jars plugin requires maven 3.0.3+

OSX show used ports or listening applications with their PID

On OSX you can display applications listening on a given port using the lsof the commands described below will show listening application...