Pages

Sunday, November 18, 2012

How to read a dynamically growing file with Java?

This small post explains, how to read a text file which grows dynamically, using Java. The catalina.out file which displays tomcat's console is a good example for a file which grows dynamically. 

The following example shows, how to read tomcat's catalina.out file with Java. This file grows when the applications deployed on tomcat are being accessed by users. The following program displays newly adding contents of catalina.out file just one second delay and keep continuing it. 

The Java's 'RandomAccessFile' class provides great facilities to read this kind of files.  The major usage of it for the following program is, it provides a feature so that we can read a file from a particular point to onwards. Let's see our small program. 

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Timer;
import java.util.TimerTask;


public class ConsoleReader {

   /**
    * @param args
    */
    public static void main(String[] args) {
    File file = new File("/home/semika/apache-tomcat-7.0.25/logs/catalina.out");
       try {
           RandomAccessFile r = new RandomAccessFile(file, "r");
           //First time read
           String str = null;
           while((str = r.readLine()) != null) {
            System.out.println(str);
           }
           r.seek(r.getFilePointer());
           startTimer(r);
       } catch (FileNotFoundException e) {
           e.printStackTrace();
       } catch (IOException e) {
           e.printStackTrace();
       } 
    }
 
    private static void startTimer(final RandomAccessFile r) {
     Timer timer = new Timer();
     timer.scheduleAtFixedRate(new TimerTask() {
     @Override
     public void run() {
     String str = null;
     try {
          while((str = r.readLine()) != null) {
           System.out.println(str);
          } 
          r.seek(r.getFilePointer()); 
     } catch (IOException e) { 
         e.printStackTrace();
     }
      }
 }, 0, 1000);
    }
}

In the above program, it reads catalina.out file line by line and displays it in console. When you run the program, it will read the whole file up to the end at first and then immediately start a timer to read dynamically adding contents to the file. The timer will always start to read file from a particular point, in above case, it will always start to read the file from the next line which last line was displayed.

While you are accessing your applications deployed in your tomcat container, just keep looking at the output of above program. You can see the tomcat's console just like, you have used to see it before.

Monday, November 12, 2012

Java enums are more than constant fields.

An enum is a type which defines set of fixed constants. For example, if you think generally, the seasons of the year, the planets in the solar system can be defined as enums. Also, you can identify constant types  in your application and defined those as enums which gives you much reliability, maintainability and also the flexibility. Enums were introduced to the Java language with 1.5 release which provides great functionality than what we know, and what we are using. Before introducing enums to the language, we used int, string constants which have many shortages. 

With this post, I am going to discuss the advantages of using enums and the shortcomings of using traditional constants approach. Suppose, we want to keep constant types for seasons of the year. Before enum was introduced, we normally defined a constant group as follows. 

 public static final int SEASON_SPRING = 3;
 public static final int SEASON_SUMMER = 6;
 public static final int SEASON_AUTUMN = 9;
 public static final int SEASON_WINTER = 12;
The value assigned for each field is, the starting month of the season. For example, the summer season will start from 6th month of the year. In real world, the starting month of each season will vary from country to country. I used above values just for illustration purpose. 

Let's discuss the shortcomings of the above approach when comparing with enum types. 

Constant fields don't provide type safety. Suppose you have written a method which returns the months belong to each season.

private List<String> getMonthsOfSeason(int seasonStartingMonth) {
  
    switch(seasonStartingMonth) {
       case 3:
           return CalendarUtil.getMonthsOfYear(new int[]{2,3,4});
           //[March, April, May]
       case 6:
           return CalendarUtil.getMonthsOfYear(new int[]{5,6,7});
           //[June, July, August]
       case 9:
           return CalendarUtil.getMonthsOfYear(new int[]{8,9,10});
           //[September, October, November]
       case 12:
           return CalendarUtil.getMonthsOfYear(new int[]{11,0,1});
           //[December, January, February]
       default:
           return new ArrayList<String>(); 
    }
}

If we use traditional int constants approach, we have to implement similar method like above to get the months of a season. I will show you the code for CalendarUtil class later in this post.

The above method accepts any integer value as the season starting month. By mistakenly, you may pass a different integer constant field (some number except 3,6,9,12) into the method instead of passing one of the season number which has been defined as constants above. In that kind of scenario, the method will returns empty list which may result unexpected output.

Though, You can add considerable validation to the above method, still that method is brittle. The other thing is, you may compare the parameter value with any integer since defined constants are integer type.

   
   If(seasonStartingMonth == QUATER_THREE) {
     //some code
   }

In the above code 'QUATER_THREE' is some different integer constant field defined in the same class for different purpose. Our programmer has mistakenly compared 'seasonStartingMonth' variable with QUATER_THREE constant field. But this is valid comparison, no compile error, but it will give wrong output. Programmer actually intended to compare 'seasonStartingMonth' variable with one of the our defined season constant field. 

Java does not provide namespaces to distinguish each constant groups. We have to use prefixes when two int constant groups have identically named fields. I have used SEASON_ for season group for that purpose. 

The int constants are compile-time constants. The int enums are compiled into the clients that use them. If the int associated with an enum constant is changed, its clients must be recompiled. If they aren’t, they will still run, but their behaviour will be undefined. 

The int constants don't give good debugging information. The int constant fields do not give helpful information when you are debugging your code. If you print some int constant field, it will print just a number which does not make sense. There is no easy way to translate int constant fields into printable strings. 

There is no reliable way to iterate over all the constants defined in a particular constant group and also the size of the constant group. 

Above, I have highlighted some of the shortcoming when using traditional constant field approach.

I have small utility class as follows.

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;


public final class CalendarUtil {

    //Returns list of names of the months for a given array of month numbers.
    public static List<String> getMonthsOfYear(int[] months) {
         List<String> monthArray = new ArrayList<String>(3);
         Calendar cal = Calendar.getInstance();

         for (int i = 0; i < months.length; i++) {
             cal.set(Calendar.MONTH, months[i]);
             monthArray.add(cal.getDisplayName(Calendar.MONTH,
                    Calendar.LONG, Locale.ENGLISH));
         }
         return monthArray;
    }
}

In the above utility class, the 'getMonthsOfYear()' method returns list of month's name for a given array of month numbers of the year.

Now,let's try to do the same thing by using enum. The following code shows an enum definition for seasons of the year.

import java.util.ArrayList;
import java.util.List;

public enum Season {

   SEASON_SPRING(3), //[March, April, May]
   SEASON_SUMMER(6), //[June, July, August]
   SEASON_AUTUMN(9), //[December, January, February]
   SEASON_WINTER(12);//[September, October, November]
 
   private final int startingMonth;
 
   SEASON(int startingMonth) {
       this.startingMonth = startingMonth;
   }
 
   public List<String> getMonthsOfSeason() {

       switch(startingMonth) {
           case 3:
             return CalendarUtil.getMonthsOfYear(new int[]{2,3,4});
           case 6:
             return CalendarUtil.getMonthsOfYear(new int[]{5,6,7});
           case 9:
             return CalendarUtil.getMonthsOfYear(new int[]{8,9,10});
           case 12:
             return CalendarUtil.getMonthsOfYear(new int[]{11,0,1});
           default:
             return new ArrayList$lt;String>(); 
       }
    }
}

See how Java enums are smart? Java enums are classes that export one instance for each enumeration constant via a public static final field. This kind of enum declaration provides compile time safety. For example, consider the following method.

private List<String> getMonthsOfSeason(Season season) {

}

This method guaranteed that it won't accept any other types of values except Season. If we try to pass some other types, compiler will point it out as an error. 

Since Java enum has it's own namespace, identically named constants can coexist with out any problem. For example, We can use same enum constant field name with another enum declaration. 

We can easily convert enum constant fields to printable string using toString() method.

Java enum allows us to keep methods and fields associated with it. In the above example, I have declared one field and method with the enum. I have defined the method with the enum it self which returns months of the season. This is very reliable and convenience implementation. The likelihood of happening bugs in the application is comparatively less. If we want to get the months of winter seasion, we can do it as follows.

List<String> months = Season.SEASON_WINTER.getMonthsOfSeason();

In the above example, the defined method behaves similarly for every constant field. But, We can implement method which behaves differently for each constant field on the enum. I have discussed about field specific method implementation with another post. Please have a look on following URL.

http://skillshared.blogspot.com/2012/01/java-enum-constant-specific-method.html

We can associate data with each constant field of a enum. I have specified starting month number with each constant field of Season enum. We can associate data as many with the enum constant field with the declared fields with corresponding types of data and also the constructor parallel to those data. Enums are immutable, so all fields should be final.

Also, if you want to iterate over all the constant fields of the enum, you can do it as follows.

for (Season s : Season.values()) {
   System.out.println("Months of seasion : " + s.toString());
   System.out.println(s.getMonthsOfSeason());
}

I am going to conclude this article with nice example. Consider the eight planets of our solar system. There are tow constant attribute for each planet has, a mass and a radius, and from these two attributes you can compute its surface gravity. This in turn lets you compute the weight of an object on the planet’s surface, given the mass of the object. Here’s how this enum looks.The numbers in parentheses after each enum constant are parameters that are passed to its constructor. In this case, they are the planet’s mass and radius.
public enum Planet {
    MERCURY(3.302e+23,2.439e6),
    VENUS (4.869e+24,6.052e6),
    EARTH (5.975e+24,6.378e6),
    MARS(6.419e+23,3.393e6),
    JUPITER(1.899e+27,7.149e7),
    SATURN (5.685e+26,6.027e7),
    URANUS (8.683e+25,2.556e7),
    NEPTUNE(1.024e+26,2.477e7);

    private final double mass;
    private final double radius;
    private final double surfaceGravity;

    private static final double G = 6.67300E-11;

    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
        surfaceGravity = G * mass / (radius * radius);
   }

   public double mass() {
         return mass;
   }

   public double radius() {
         return radius;
   }

   public double surfaceGravity() {
         return surfaceGravity;
   }

   public double surfaceWeight(double mass) {
        return mass * surfaceGravity;
   }
}

Sunday, November 11, 2012

How to display months of the year with Java?

The Calendar is very useful utility class provided by Java for manipulating calender fields. It represents months of the year in integer format starting from 0 and ending with 11, which 0 represents 'January' and 11 represents 'December'. The 'getDisplayName' method of Calendar class returns the string representation of the calendar field value in the given style and locale. If no string representation is applicable, null is returned. 

The following Java program displays months of the year in two formats.

import java.util.Calendar;
import java.util.Locale;

public class CalendarUtil {

    public static void main(String[] args) {
        displayMonthsInLongFormat();
        displayMonthsInShortFormat();
    }
 
    private static void displayMonthsInLongFormat() {
  
        Calendar cal = Calendar.getInstance();
  
        System.out.println("Months of the year in long format");
        System.out.println("---------------------------------");
  
        for (int i = 0; i < 12; i++) {
            cal.set(Calendar.MONTH, i);
   
             System.out.println(cal.getDisplayName(Calendar.MONTH, 
                           Calendar.LONG, Locale.ENGLISH));; 
        }
     }
 
     private static void displayMonthsInShortFormat() {
  
         Calendar cal = Calendar.getInstance();
  
         System.out.println("Months of the year in short format");
         System.out.println("---------------------------------");
  
         for (int i = 0; i < 12; i++) {
             cal.set(Calendar.MONTH, i);
   
             System.out.println(cal.getDisplayName(Calendar.MONTH, 
                       Calendar.SHORT, Locale.ENGLISH));; 
         }
     } 
}
The above program will generate the following output.

Months of the year in long format ---------------------------------
January
February
March
April
May
June
July
August
September
October
November
December

Months of the year in short format ---------------------------------
Jan
Feb
Mar
Apr
May
Jun
Jul
Aug
Sep
Oct
Nov
Dec

Saturday, November 10, 2012

How to run Ant targets with Maven?

The maven-antrun-plugin allows us to run ant targets with various maven build phases. I am going to explain very practical usage of maven-antrun-plugin specially for developers with development environment.

Normally with maven build, you will bundle your project either to a war file or ear file. You can directly copy this war or ear file into the server deployment folder by using maven-antrun-plugin. If your sever is tomcat, you can directly copy your archive file to 'webapps' folder easily.  Some developers are used to copy the archive file to the server deployment folder manually even with their development. For them, this post will be very helpful.

If you want to use maven-antrun-plugin to copy your archive file into the server deployment folder every time when you build the project, you can add the following plugin into your pom.xml file and use what ever the ant targets as you wish.

Which pom.xml file, I am going to put this plugin to?

That is a good question. If you have multi module project, you should probably have either ear module or war module. Select the pom.xml file of that module and place the following plugin there. When you buld that project module, most of the time, it will be the last module bulding when you build your project in root level, maven will create either war file or ear file inside the target directory of your project module. We can configure maven-antrun-plugin so that it will copy that war file or ear file into server deployment folder.

In my case, I have multi module project and one module is a web module. I should place the the maven-antrun-plugin into web module's pom.xml file.

<build>
    <finalName>shims-web</finalName>
    <plugins>
        <plugin>
            <artifactId>maven-antrun-plugin</artifactId>
            <version>1.7</version>
            <executions>
                <execution>
                    <phase>install</phase>
                    <configuration>
                          <target>
                              <copy file="${project.build.directory}/shims-web.war" todir="${env.CATALINA_HOME}/webapps"/>
                          </target>
                    </configuration>
                    <goals>
                         <goal>run</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

If you inspect the above snip of pom.xml file, I have given 'install' as the phase of execution. It simply says that "execute this ant target just after the install life cycle phase" of the maven build. With the execution of 'install' , maven will the package the whole project into the local repository as a war file or ear file, for use as a dependency in other projects locally. Also this will create the same file in the target directory of your workspace as well.

Our target is to copy that file from target director to server deployment folder with the build. The  ${env.CATALINA_HOME} will refer to the our tomcat installation directory.

Now build the your project or project module. You can navigate to your project directory or project module directory where our modified pom.xml is. Run the following command.

$mvn clean install

The above command will traverse into all of the sub projects and run clean, then install (including all of the prior steps). You can run that command in root project level which build the entire project, or you can run it for specific project module, which build only that project.


.......................
[INFO] --- maven-antrun-plugin:1.7:run (default) @ shims-web ---
[INFO] Executing tasks
main:
         [copy] Copying 1 file to /home/vinesh/apache-tomcat-7.0.25/webapps
[INFO] Executed tasks
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS ........................

If you are using m2eclipse to build your project, sometime, you may encounter strange scenario as follows. We hope maven will copy our archive file to the deployment folder of the server with the build completion. But sometime, maven will copy our archive file into the project workspace folder itself by creating the directories structure which we have mentioned as the destination directory in our pom.xml file of our ant copy target.

For example, in this case, it will create following directory structure in our local workspace folder rather than copying the file into the server folder. Just have a look on following image.

We are not expecting this scenario.

How can we overcome this?

You have to edit maven build target in eclipse by specifying the CATALINA_HOME environment variable. 

You can do this as follows.

Open "Run Configurations" window in eclipse and expand "Maven Build" category. You can see all the maven targets, you have created so far, have been listed there. Select the maven target which build your project with "clean install" goal.

And then open "Environment" tab. There you can add new variable for the CATALINA_HOME environmental variable as follows.

Click on 'Apply' button and then run your maven target again. Look into your eclipse console carefully. You can see that maven is copying your archive file into server deployment folder.

You may also like:

Thursday, November 8, 2012

How to list down all maven available properties?

It will be very important for you to know all the available maven properties when you are working with maven project. We know few properties. Some of those properties are ${project.groupId}, ${project.version} and few more. I intended to give you a technique to find out all the available properties given by maven which will be very helpful for you. 

Here is the way. You can create a new simple maven project. It may be either jar project or war project. Even you can use one of your existing project too. Open the project pom.xml file and see the following section is in your pom.xml file.

<build>
    <plugins>
        <plugin>
             ..............
        </plugin>
   </plugins>
</build>

Since, We are going to use maven-antrun-plugin, we need to add this plugin into our project pom.xml file. If the above section is not in our pom.xml file, you have to add above section into your pom.xml file. Next copy and past the following plugin inside <plugins> section.
<plugin>
    <artifactId>maven-antrun-plugin</artifactId>
    <version>1.7</version>
    <executions>
         <execution>
              <phase>install</phase>
              <configuration>
                    <target>
                        <echoproperties />
                    </target>
              </configuration>
              <goals>
                  <goal>run</goal>
              </goals>
         </execution>
    </executions>
</plugin>

The maven-antrun-plugin allows us to run ant targets with maven. The above ant target will execute when we run 'clean install' maven goal. Notice that I have specified 'install' as the phase which means that this ant target will execute with the maven 'install' goal runs. Navigate to your project directory using command line.

$cd <path to your project directory>
$mvn clean install

It will start the building the project and meanwhile, lists down all the maven properties. You will get similar output as follows.
[echoproperties] #Ant properties
[echoproperties] #Thu Nov 08 19:57:30 IST 2012
[echoproperties] ant.core.lib=/home/vinesh/.m2/repository/org/apache/ant/ant/1.8.2/ant-1.8.2.jar
[echoproperties] ant.file=/home/vinesh/workspace-maaven/shims/shims-web/pom.xml
[echoproperties] ant.file.maven-antrun-=/home/vinesh/workspace-maaven/shims/shims-web/target/antrun/build-main.xml
[echoproperties] ant.file.type.maven-antrun-=file
[echoproperties] ant.java.version=1.6
[echoproperties] ant.project.default-target=main
         ....................
         ....................
If you don't know how to create maven projects, please look the following URL. 

How to create multi module project with maven.

 
You may also like:

Wednesday, November 7, 2012

Why @Override annotation is important in Java?

The 'Override' annotation was introduced with Java 1.5 release which indicates that the annotated method declaration overrides the declaration in a super class. This annotation is used highly and most of the modern IDE's added this annotation automatically when we use some IDE's features. If you consistently use this annotation, it will protect you from a large class of sever bugs. Let's have some example. Consider the following class declaration.

public class Employee {

    private String nicNo;
    private String name;
 
    public Employee(String nicNo, String name) {
         super();
         this.nicNo = nicNo;
         this.name = name;
    }
    public String getNicNo() {
         return nicNo;
    }
    public void setNicNo(String nicNo) {
         this.nicNo = nicNo;
    }
    public String getName() {
         return name;
    }
    public void setName(String name) {
         this.name = name;
    }
    public int hashCode() {
         final int prime = 31;
         int result = 1;
         result = prime * result + ((nicNo == null) ? 0 : nicNo.hashCode());
         return result;
    }
    public boolean equals(Employee obj) {
         return obj.nicNo == this.nicNo;
    }
}

Sunday, November 4, 2012

Reduce the scope of local variable in Java

Old programing languages such as C,C++ force us to declare local variables at the head of the code block. Some programers used to continue the same with Java. But it is not a good practice though Java lets us declare local variable anywhere in the code.

The most easy way to reduce the scope of local variable is, declare local variables where it is first used. This will reduce the scope of local variables and also this will increase the code readability. If you declare your local variable at top of code block or method, by the time that variable is used, the code reader might not remember about the variable.

With this small post, I am going to give you an example which creates a bug in the application which is very hard to detect. We know that "Loops" have a special opportunity to minimize the scope of variables. The traditional for loop and new for-each loop allows you to declare loop variables limiting their scopes to the region where they are needed. 

Saturday, November 3, 2012

How to create multi module project with maven?

It is more than three years, I have started to use maven and it is a great tool, I have ever used. The support of repository management and the features available to create multi module project are excellent. With this tutorial, I am going to show you, how to create a multi module project with maven. I am using eclipse as IDE and 'm2eclipse' plugin for eclipse.

The following picture shows the project structure in eclipse.

My project is 'shims' and it has two modules as 'shims-core' and 'shims-web'. One module contains all business logic classes and data access objects which is bundled as jar file. And the other module is the web module which contains controller related classes (Struts2 action or Servlets or Spring controller classes) and view related stuff.

The tutorial summary is as follows.
Installing maven

Download the Apache maven distribution and extract it some where in your computer. You can download the apache maven from here. I have extracted the distribution into the following location in my computer.

/home/vinesh/apache-maven-3.0.4

Next, You have to set 'MAVEN_HOME' environmental variable and add the path of maven's bin folder to classpath. In Ubuntu, you can set the variable as follows. You have to add the following two lines into bashrc file. First, run the following command to open 'bashrc' file.

$ vi ~/.bashrc

And add the following two lines.

export MAVEN_HOME=/home/vinesh/apache-maven-3.0.4
export PATH=$MAVEN_HOME/bin:$PATH

In windows, setting an environment variable is not that much difficult. So I am not going to explain that in this tutorial.

After editing 'bashrc' file, just open a command window and run the following command.

$ mvn -version

If you get the output similar to following, you are successfully configured apache maven.

Apache Maven 3.0.4 (r1232337; 2012-01-17 14:14:56+0530)
Maven home: /home/semika/apache-maven-3.0.4
Java version: 1.6.0_30, vendor: Sun Microsystems Inc.
Java home: /home/semika/java/jdk1.6.0_30/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "2.6.38-16-generic", arch: "amd64", family: "unix"

You are done with the first step and let's move to next step.  

Configure m2eclipse, maven with eclipse 

You have to install m2eclipse plugin first. You can install m2eclipse plugin via eclipse it self. I am using eclipse 'Indigo' version and there may be slight differences with other version of eclipse. 

This is the update URL for m2eclipse.

http://download.eclipse.org/technology/m2e/releases

Go to Help --> Install New Software. You will get the following window.



You can add the above update URL and continue the wizard. Normally this will take some time and after finishing the installation, you have to restart the eclipse. Go to Window -->Preferences. You should see that 'Maven' category has added to preferences categories.


We are not going to use embedded maven coming with the plugin as I have highlighted in the above image. Instead, we are going to configure our maven installation with eclipse. 

Click the 'Add' button and locate your maven installation directory. For further clarification see the image bellow. 


You can see now, the plugin has been configured with our maven installation. Now, you are ready to create projects using m2eclipse. Let's start to create our multi module project.

Eclipse provides great facilities to create multi module projects and relationships among the modules. In this tutorial, I am going to create a maven multi module projects from the scratch.




 
Creating maven parent project

Step01: Go to File --> New --> Project.

You will get 'New Project' window. Under 'Maven' category, select 'Maven Project'. Click 'Next' button. You will get 'New Maven Project' window. See the bellow image.



Step 02: We are going to create simple maven project. As I have pointed out from right side image, make sure to check 'Create a simple project' checkbox. Click on 'Next' button. Then you will get the following window.

I feel, it is better to give little explanation about the four fields highlighted with red color box in the right side image.

Group Id: This is the root packaging structure of your project. Make sure to use the same root package structure for every module in the project. 

Artifact Id : This is similar to your project module name. In right side image, I have given 'shims' as the artifact id. That is the parent project of my all project modules.

Packaging: This is very important when creating multi module project with maven. There are several options which you can select as the packaging. If you want to create a parent project, we are doing like now, you have to select 'pom' as the packaging. To create Java module, select 'jar' and for web module, select 'war'. I will explain later on this tutorial, how to create a 'jar' and 'war' module. You know that 'shims-core' is a jar module which contains all the business logic and data access objects and 'shims-web' is a web module containing all controller  and view related stuff.

Click the 'Finish' button and see, maven is creating the parent project for our multi module project. Let's little examine this.

Open the 'pom.xml' file. It should be similar to the following.


<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">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.semika</groupId>
  <artifactId>shims</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>
</project>


Let's create our first child module.  

Creating maven child jar module

We want to keep our all business logic and DAO classes as a separate module which can be bundled to as a 'jar' file. We can create a separate project module for this purpose. In my sample application, it has 'shims-core' module. This is a child module of our parent project which we already created. 

To create child jar module.

Step 01: Right click on the parent project, Go to New-->Project. Select the 'Maven Module' from the 'Maven' category. As you can remember, we selected 'Maven Project' when we create our parent project before. Since we are creating a project module now, we should select 'Maven Module'. 

Click the 'Next' button. You will get 'New Maven Module' window as follows.



Make sure to check 'Create a simple project' check box and give a module name. You can see that 'shims' which is our parent project has automatically selected as the 'Parent Project'. We are in a correct way. Click the 'Next' button. You will get familiar window as follows.


As You can see in the right side image, 'Group Id', 'Artifact Id' and 'Version' have already been set by default. We don't need to change any of those three field values. Keep those values as it is. Since we are creating 'jar' module, we should select 'jar' as the packaging. Click the 'Finish' button and see maven is creating our first child module.

Now refresh the parent project and notice that maven has created a new project 'shims-core' inside the 'shims'. The 'shims-core' represents a another maven project module which has separate pom.xml file. Also 'shims-core' represents as the new project within eclipse.

Just have a look on following image.

Now, If you see parent project's pom.xml file, you can see that 'shims-core' has listed under modules which says that 'shims-core' is a child module of 'shims' parent project.

  <modules>
   <module>shims-core</module>
  </modules>

Also, in the child project's pom.xml file, it has a reference to parent project. Further, in child module's pom.xml file, 'groupId' and 'version' have not been defined. Those are inherited from parents project. This is good practice when you are creating multi module project with maven.
  <parent>
    <artifactId>shims</artifactId>
    <groupId>com.semika</groupId>
    <version>1.0-SNAPSHOT</version>
    <relativePath>..</relativePath>
  </parent>


Creating child war module

Next, we will create our web module, 'shims-web' which contains our controller classes and other view related stuff. Creating war module with m2eclipse is little different rather creating jar module. We have to use one of the maven pre-defined archetype  for web module creation. Don't worry, I will give you step by step explanation about creating maven war module. 

Step 01: Right click on parent project, Go to New-->Project and select 'Maven Module', Click 'Next' button.

In this case, we are not going to create a simple project. So don't check on 'Create simple project' check box. As you can see from the right side image, parent project has automatically selected as 'shims' which is our parent project. You have to specify the module name as 'shims-web'. and click 'Next' button.




Step 02: Click the 'Next' button from the above image. We are going to use 'maven-archetype-webapp' artifact to create our war module. See the bellow image.


Step 03: Click 'Next'  button from above window and you will get the following window.


You only need to change the 'Package' from right side window. Click the 'Finish' button and let the maven create our web module. After creating the new web module, refresh the parent project and notice that it has a new module as 'shims-web'. So now we have a multi module project with tow modules. Open pom.xml file from the web module and make sure to remove 'groupId' and 'version'. Also see the parent project's pom.xml file and notice that 'shims-web' has been added to it as a new module.

We hope to deploy our application as a war bundle into the server. If you want to change you war file name, you can change 'filaName' attribute of pom.xml file of 'shims-web' module.


  <build>
    <finalName>shims-web</finalName>
  </build>

This will create 'shims-web.war' file under 'target' directory of 'shims-web' module. Next, we need to define dependencies between 'shims-core' and 'shims-web' module. This will force the maven reactor to build 'shims-core' module before building 'shims-web' module when we run maven build from the parent project. Because, we want to bundle our business logic and DAO related classes into a separate jar module and give it to web module as a separate library along with other libraries, core module should be build before web module.

Place the following contents inside the 'dependencies' section of pom.xml file of 'shims-web' module.

    <dependency>
        <groupId>${project.groupId}</groupId>
        <artifactId>shims-core</artifactId>
        <version>${project.version}</version>
    </dependency>

${project.groupId} and ${project.version} are two global references of maven which provides 'groupId' and 'version' across the whole modules of the multi module project. We can directly use it.

Building multi module project

There are lots of advantages of creating multi module project. We can build the entire project at once and also we can build each module separately. Developers can separately work on different modules at the same time without depending on others. Other thing is, we have clear separation which enhance maintainability.
We have to create maven targets to build our project. Right click on parent project. Go to Run As --> Maven Build. You will get the following window only for the very first time. There you can create a new target to build your project. 
The right side window allow you to create maven target to build your project. You have to give a name for your build target and browse the required project module directory. Since I am going to create this maven target to build the entire project, I have located my parent directory. Put 'clean install' into the Goals field.
Since, we are going to build our project very first time, we should allow maven to download the required dependencies from their global repository. Make sure 'offline' check box 'unchecked'. After first success build, you can update this target to run it in offline mode by selecting 'offline' check box.
Make sure 'Maven Runtime' has been set to our maven installation directory. Otherwise you will get build errors.

OK!. That's it. You are ready to build your first maven multi module project. Good luck!

Click on 'Apply' and then 'Run' button. Maven will start the building project. See carefully eclipse console. It says full story. You should get 'SUCCESS' message at the end of the build. Similar output as follows.

-------------------------------------
[INFO] Installing /home/vinesh/workspace-maaven/shims/shims-web/pom.xml to /home/vinesh/.m2/repository/com/semika/shims-web/1.0-SNAPSHOT/shims-web-1.0-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] [INFO] shims ............................................. SUCCESS [1.093s]
[INFO] shims-core ........................................ SUCCESS [2.005s]
[INFO] shims-web Maven Webapp ............................ SUCCESS [1.027s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.354s
[INFO] Finished at: Sat Nov 03 22:37:27 IST 2012
[INFO] Final Memory: 6M/103M
[INFO] ------------------------------------------------------------------------

Let's deploy our application. I am using Apache tomcat7 to deploy my application. If you see inside the target directory of 'shims-web' module after the successful build, you can see,maven has create 'shims-web.war' file. Copy that file into tomcat's webapps folder and start the tomcat.

Point your browser the following URL.

http://localhost:8080/shims-web/

You should get hello world page. 


You may also like:

Thursday, November 1, 2012

Full stack trace for "SEVERE: Error listenerStart"

One of the very painful error, I have received when starting the tomcat 'SEVERE: Error listenerStart'. I can not even understand why tomcat is giving errors in such a poor manner by wasting lots of our time. This is server error, but it does not give enough information to get rid of that. 

As it says, this may be some configuration problems which failed creation of some listener. For example, it may be some problem with your spring configuration which prevents creating ContextLoaderListener.

Sometime, this may be a problem of misconfiguration of a filter. You may have configured a filter in web.xml, but the relevant filter class is not found. 
Most of you will happy, if we can get the full stack trace of above exception.You can create 'logging.properties' file in your project source so that, it will be in 'classes' folder  of your deployment archive. You can place it within 'src' folder or within 'resources' folder in your source based on your project type. The project may be tomcat project or maven project or dynamic web project. 

After creating that file, place the following contents within it.

org.apache.catalina.core.ContainerBase.[Catalina].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].handlers = java.util.logging.ConsoleHandler

Now try to start the tomcat and you will see full stack trace of above poor indication.
You may also like:
Share

Widgets