Showing posts with label embedded. Show all posts
Showing posts with label embedded. Show all posts

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

MongoDB spring data $elemMatch in field projection

Sometimes when querying a MongoDB document what you will actually need is an item of a given document's embedded collections

The issue with MongoDB is that mongo will filter out only first level documents that correspond to your query but it will not filter out embedded documents that do not correspond to your query criteria (i.e. If you are trying to find a specific book in a book saga) you will get the complete 'parent' documents with the entire sub collection you were trying to filter

So what can you do when you wish to filter a sub-collection to extract 1 subdocument ?

Enter the $elementMatch operator. Introduced in the 2.1 version the $elemMatch projection operator limits the contents of an array field that is included in the query results to contain only the array element that matches the predicate expressed by the operator.

Let's say I have a model like the following :

   {
     "id": "1",
     "series": "A song of ice and Fire",
     "author" : "George R.R. Martin",
     "books" : [
           {
               "title" : "A Game of Thrones",
               "pubYear" : 1996,
               "seriesNumber" : 1
           },
           {
               "title" : "A Clash of Kings",
               "pubYear" : 1998,
               "seriesNumber" : 2
           },
           {
               "title" : "A Storm of Swords",
               "pubYear" : 2000,
               "seriesNumber" : 3
           },
           {
               "title" : "A Feast for Crows",
               "pubYear" : 2005,
               "seriesNumber" : 4
           },
           {
               "title" : "A Dance with Dragons",
               "pubYear" : 2011,
               "seriesNumber" : 5
           },           
           {
               "title" : "The Winds of Winter",
               "pubYear" : 2014,
               "seriesNumber" : 6
           },           
           {
               "title" : "A Dream of Spring",
               "pubYear" : 2100,
               "seriesNumber" : 7
           }

      ]
}

Now let's say for example that I'm interested only in the 5th book of a given book series (A Song of ice and fire for example)

This can be accomplished in a number of different ways :

  • MapReduce functions : Supported by Spring data but maybe a bit cumbersome for what we are trying to accomplish (I will write in the future a tutorial on how to use MongoDB MapReduce functions with Spring Data and making those functions "templatable"
  • Mongo's aggregation framework : Version 2.1 introduced the aggregation framework that lets you do a lot of stuff (more info here ) however the aggregation framework is not currently supported by Spring Data
  • the $elemMatch operator

But what is the $elemMatch operator, and how do you use it?

Well You could say $elemMatch is a multi-purpose operator as it can be used either as part of the query but also as part of the fields object, where it acts as a simplified MapReduce kind-of :)

But as always there is a caveat though when using $elemMatch operator, and that is that if more than 1 embedded document matches your criteria, only the first one will be returned as stated MongoDB documentation

Now when using spring data with mongodb you can relatively easily do field projection using the fields() object exposed by the Query class like so :


  Query query = Query.query(Criteria.where("series").is("A song of ice and Fire"));
  query.fields().include("books");

However the Query class, even though is very easy to use and manipulate, doesn't give you access to some of Mongo's more powerful mechanisms like for example the $elemMatch as a projection operator.

In order for you to use the $elemMatch operator as a projection constraint you need to use a subclass of org.springframework.data.mongodb.core.query.Query i.e. org.springframework.data.mongodb.core.query.BasicQuery

So let's get down to business with an example.

Let's say we are interested only in the 4th book out of George R.R. Martin's saga a Song of ice and fire

Now if you were using the traditional Query class you will probably end up writing a 2 step logic that would look something like this (unless you were using a MapReduce function)

1. Retrieve the parent Book document that correspond to your search criteria


/**
*Returns the parent book corresponding to the sagaName criteria with the unfiltered child collection books
*/
public Book findBookNumberInSaga(String sagaName, Integer bookNumber){

   Query query = Query.query(Criteria.where("series").is(sagaName).and("books.seriesNumber").is(bookNumber));

   MongoTemplate template = getMongoTemplate();
   
   return template.find(query);

}


2. From the parent document iterate through the books collection (or use LambdaJ :p ) to recover the book you a really interested in


public class WithoutElememMatch{

public static void main(String[] args){

     Book saga = findBookNumberInSaga("A song of ice and Fire", 4);
     Book numberFor = null;
      
    Iterator<Book> books = saga.getBooks();

        while (books.hasNext()){
            Book  currentBook= books.next();

             if(book.getSeriesNumber() == 4){
                numberFor = currentBook;
             }           
        }
 
 }
//...
}



Even though the previous example is certantly not the best way to implement this logic, it works fine and it serves it purpose

Now let's implement the same thing but this time we will make the database work for us :

1. Fetch the book corresponding to the requested criteria but make the database do the work for you

Here we ask MongoDB to filter the elements in the sub-collection books to the one matching our criteria (i.e. the number 4 in the series)


/**
* Returns the parent book corresponding to the sagaName criteria with a size 1 collection 'children' collection whose seriesNumber
* property corresponds to the value of the seriesNumber argument
*/
public Book findBookNumberInSaga(String sagaName, Integer bookNumber){
        
        // the query object
        Criteria findSeriesCriteria = Criteria.where("title").is(title);
        // the field object
        Criteria findSagaNumberCriteria = Criteria.where("books").elemMatch(Criteria.where("seriesNumber").is(seriesNumber));
        BasicQuery query = new BasicQuery(findSeriesCriteria.getCriteriaObject(), findSagaNumberCriteria.getCriteriaObject());

        return  mongoOperations.find(query, Book.class);

}

 // omitted mongo template initialization




As you can see this time I didn't use the org.springframework.data.mongodb.core.query.Query class to build my query but instead I used the org.springframework.data.mongodb.core.query.BasicQuery class; because as I stated before you can only do projection in the field object by using these class

You will notice that the syntax for this class is a bit different as it takes 2 DbObjects (which are basically HashMaps) 1 for the query object and one for the field object. Much like the the mongo shell client syntax :

db.collection.find( ,  )

So now our method is implemented we can finally call it and check the results :


public class WithElememMatch{

public static void main(String[] args){

    // get the parent book
     Book parentBook = findBookNumberInSaga("A song of ice and Fire", 4);
      Book numberFor;
   
   // null checks
     if(book != null && CollectionUtils.isNotEmpty(book.getBooks()){
  // get the only book we are interested in
    numberFor = parentBook.getBooks().get(0);
  
  }
     
}
//...
 
}

So there you go hope this was useful to you, as usual you can find the code of this tutorial over at my github account here

Note : for this tutorial you will only find the 2 java classes mentioned earlier, there's no Spring / Spring data configuration (that's for another tutorial)

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...