Affichage des articles dont le libellé est J2EE. Afficher tous les articles
Affichage des articles dont le libellé est J2EE. Afficher tous les articles

mardi 6 décembre 2016

Top 10 Tricky Java interview questions and Answers

10 Tricky Java interview question - Answered

Here is my list of 10 tricky Java interview questions, Though I have prepared and shared lot of difficult core Java interview question and answers, But I have chosen them as Top 10 tricky questions because you can not guess answers of this tricky Java questions easily, you need some subtle details of Java programming language to answer these questions.
Question: What does the following Java program print?
public class Test {
    public static void main(String[] args) {
        System.out.println(Math.min(Double.MIN_VALUE, 0.0d));
    }
}
Answer: This question is tricky because unlike the Integer, where MIN_VALUE is negative, both the MAX_VALUE and MIN_VALUE of the Double class are positive numbers. The Double.MIN_VALUE is 2^(-1074), a double constant whose magnitude is the least among all double values. So unlike the obvious answer, this program will print 0.0 because Double.MIN_VALUE is greater than 0. I have asked this question to Java developer having experience up to 3 to 5 years and surprisingly almost 70% candidate got it wrong.

What will happen if you put return statement or System.exit () on try or catch block? Will finally block execute?
This is a very popular tricky Java question and it's tricky because many programmers think that no matter what, but the finally block will always execute. This question challenge that concept by putting a return statement in the try or catch block or calling System.exit() from try or catch block. Answer of this tricky question in Java is that finally block will execute even if you put a return statement in the try block or catch block but finally block won't run if you call System.exit() from try or catch block.


Question: Can you override a private or static method in Java?
Another popular Java tricky question, As I said method overriding is a good topic to ask trick questions in Java. Anyway, you can not override a private or static method in Java, if you create a similar method with same return type and same method arguments in child class then it will hide the superclass method, this is known as method hiding.
Similarly, you cannot override a private method in sub class because it's not accessible there, what you do is create another private method with the same name in the child class.



Question: What do the expression 1.0 / 0.0 will return? will it throw Exception? any compile time error?
Answer: This is another tricky question from Double class. Though Java developer knows about the double primitive type and Double class, while doing floating point arithmetic they don't pay enough attention to Double.INFINITY, NaN, and -0.0 and other rules that govern the arithmetic calculations involving them. The simple answer to this question is that it will not throw ArithmeticExcpetion and return Double.INFINITY.

Also, note that the comparison x == Double.NaN always evaluates to false, even if x itself is a NaN. To test if x is a NaN, one should use the method call Double.isNaN(x) to check if given number is NaN or not. If you know SQL, this is very close to NULL there. 
Does Java support multiple inheritances?
This is the trickiest question in Java if C++ can support direct multiple inheritances than why not Java is the argument Interviewer often give. Answer of this question is much more subtle then it looks like, because Java does support multiple inheritances of Type by allowing an interface to extend other interfaces, what Java doesn't support is multiple inheritances of implementation. This distinction also gets blur because of default method of Java 8, which now provides Java, multiple inheritances of behavior as well.


What will happen if we put a key object in a HashMap which is already there?
This tricky Java question is part of another frequently asked question, How HashMap works in Java. HashMap is also a popular topic to create confusing and tricky question in Java. Answer of this question is if you put the same key again then it will replace the old mapping because HashMap doesn't allow duplicate keys. The Same key will result in the same hashcode and will end up at the same position in the bucket.
 Each bucket contains a linked list of Map.Entry object, which contains both Key and Value. Now Java will take the Key object from each entry and compare with this new key using equals() method, if that return true then value object in that entry will be replaced by new value.



Question: What does the following Java program print?
public class Test {
    public static void main(String[] args) throws Exception {
        char[] chars = new char[] {'\u0097'};
        String str = new String(chars);
        byte[] bytes = str.getBytes();
        System.out.println(Arrays.toString(bytes));
    }
}

Answer: The trickiness of this question lies on character encoding and how String to byte array conversion works. In this program, we are first creating a String from a character array, which just has one character '\u0097', after that we are getting the byte array from that String and printing that byte. Since \u0097 is within the 8-bit range of byte primitive type, it is reasonable to guess that the str.getBytes() call will return a byte array that contains one element with a value of -105 ((byte) 0x97).

However, that's not what the program prints and that's why this question is tricky. As a matter of fact, the output of the program is operating system and locale dependent. On a Windows XP with the US locale, the above program prints [63], if you run this program on Linux or Solaris, you will get different values.

To answer this question correctly, you need to know about how Unicode characters are represented in Java char values and in Java strings, and what role character encoding plays in String.getBytes().

In simple word, to convert a string to a byte array, Java iterate through all the characters that the string represents and turn each one into a number of bytes and finally put the bytes together. The rule that maps each Unicode character into a byte array is called a character encoding. So It's possible that if same character encoding is not used during both encoding and decoding then retrieved value may not be correct. When we call str.getBytes() without specifying a character encoding scheme, the JVM uses the default character encoding of the platform to do the job.

The default encoding scheme is operating system and locale dependent. On Linux, it is UTF-8 and on Windows with a US locale, the default encoding is Cp1252. This explains the output we get from running this program on Windows machines with a US locale. No matter which character encoding scheme is used, Java will always translate Unicode characters not recognized by the encoding to 63, which represents the character U+003F (the question mark, ?) in all encodings.


If a method throws NullPointerException in the superclass, can we override it with a method which throws RuntimeException?
One more tricky Java questions from the overloading and overriding concept. The answer is you can very well throw superclass of RuntimeException in overridden method, but you can not do same if its checked Exception.


What is the issue with following implementation of compareTo() method in Java
public int compareTo(Object o){
   Employee emp = (Employee) o;
   return this.id - e.id;
}
where an id is an integer number.
Well, three is nothing wrong in this Java question until you guarantee that id is always positive. This Java question becomes tricky when you can't guarantee that id is positive or negative. the tricky part is, If id becomes negative than subtraction may overflow and produce an incorrect result.



How do you ensure that N thread can access N resources without deadlock?
If you are not well versed in writing multi-threading code then this is a real tricky question for you. This Java question can be tricky even for the experienced and senior programmer, who are not really exposed to deadlock and race conditions. The key point here is ordering, if you acquire resources in a particular order and release resources in the reverse order you can prevent deadlock.


Question: Consider the following Java code snippet, which is initializing two variables and both are not volatile, and two threads T1 and T2 are modifying these values as following, both are not synchronized
int x = 0;
boolean bExit = false;

Thread 1 (not synchronized)
x = 1; 
bExit = true;

Thread 2 (not synchronized)
if (bExit == true) 
System.out.println("x=" + x);
Now tell us, is it possible for Thread 2 to print “x=0”?

Answer: It's impossible for a list of tricky Java questions to not contain anything from multi-threading. This is the simplest one I can get. Answer of this question is Yes, It's possible that thread T2 may print x=0.Why? because without any instruction to compiler e.g. synchronized or volatile, bExit=true might come before x=1 in compiler reordering. Also, x=1 might not become visible in Thread 2, so Thread 2 will load x=0. Now, how do you fix it?

 When I asked this question to a couple of programmers they answer differently, one suggests to make both threads synchronized on a common mutex, another one said make both variable volatile. Both are correct, as it will prevent reordering and guarantee visibility.

But the best answer is you just need to make bExit as volatile, then Thread 2 can only print “x=1”. x does not need to be volatile because x cannot be reordered to come after bExit=true when bExit is volatile.

What is difference between CyclicBarrier and CountDownLatch in Java
Relatively newer Java tricky question, only been introduced from Java 5. The main difference between both of them is that you can reuse CyclicBarrier even if Barrier is broken, but you can not reuse CountDownLatch in Java.

What is the difference between StringBuffer and StringBuilder in Java?
Classic Java questions which some people think tricky and some consider very easy. StringBuilder in Java was introduced in JDK 1.5 and the only difference between both of them is that StringBuffer methods e.g. length(), capacity() or append() are synchronized while corresponding methods in StringBuilder are not synchronized.

Because of this fundamental difference, concatenation of String using StringBuilder is faster than StringBuffer. Actually, it's considered the bad practice to use StringBuffer anymore, because, in almost 99% scenario, you perform string concatenation on the same thread.


Can you access a non-static variable in the static context?
Another tricky Java question from Java fundamentals. No, you can not access a non-static variable from the static context in Java. If you try, it will give compile time error. This is actually a common problem beginner in Java face when they try to access instance variable inside the main method. Because main is static in Java, and instance variables are non-static, you can not access instance variable inside main. See, why you can not access a non-static variable from static method to learn more about this tricky Java questions.

Questions for practice
  1. When doesn't Singleton remain Singleton in Java?
  2. is it possible to load a class by two ClassLoader?
  3. is it possible for equals() to return false, even if contents of two Objects are same?
  4. Why compareTo() should be consistent to equals() method in Java?
  5. When do Double and BigDecimal give different answers for equals() and compareTo() == 0. 
  6. How does "has before" apply to volatile work?
  7. Why is 0.1 * 3 != 0.3,
  8. Why is (Integer) 1 == (Integer) 1 but (Integer) 222 != (Integer) 222 and which command arguments change this.
  9. What happens when an exception is thrown by a Thread?
  10. Difference between notify() and notifyAll() call?
  11. Difference between System.exit() and System.halt() method?
  12. Does following code legal in Java? is it an example of method overloading or overriding?
  13. public String getDescription(Object obj){
       return obj.toString;
    }
    public String getDescription(String obj){
       return obj;
    }
    and
    public void getDescription(String obj){
       return obj;
    }


This was my list of Some of the most common tricky questions in Java. It's not a bad idea to prepare tricky Java question before appearing for any core Java or J2EE interview. One or two open-ended or tricky question is quite common in Java interviews.

jeudi 26 novembre 2015

40 Most Asked Java Interview Programs With Solutions

40 Most Asked Java Interview Programs With Solutions

1) How to reverse a string in java?
2) How to create a pyramid of numbers in java?
3) How do you remove all white spaces from a string in java?
4) How to find duplicate characters in a string in java?
5) How do you check the equality of two arrays in java?
6) Anagram program in java
7) Armstrong number program in java
8) How to find duplicate elements in an array?
9) How to find sum of all digits of a number in java?
10) How to find second largest number in an integer array?
11) How to perform matrix operations in java?
12) How to count occurrences of each character in a string in java?
13) How to find largest number less than a given number and without a given digit?
14) How to find all pairs of elements in an array whose sum is equal to given number?
15) How to find continuous sub array whose sum is equal to given number?
16) How to remove duplicate elements from ArrayList in java?
17) How to check whether given number is binary or not?
18) How to check whether one string is a rotation of another in java?
19) How to find intersection of two arrays in java?
20) How to check whether user input is number or not in java?
21) How to find trigonometric values of an angle in java?
22) How to reverse each word of a string in java?
23) How to separate zeros from non-zeros in an array?
24) Decimal To Binary, Decimal To Octal And Decimal To HexaDecimal In Java
25) How to find all the leaders in an integer array in java?
26) Reverse and add until you get a palindrome
27) Selection sort in java
28) Reverse the string with preserving the position of spaces
29) Roman equivalent of a decimal number
30) percentage of uppercase, lowercase, digits and special characters in a string
31) Launch external applications through java code
32) Find missing number in an array
33) String immutable program
34) Arrays.deepToString() method example.
35) 18 Java ArrayList Programming Examples.
36) 16 Java LinkedList Programming Examples.
37) Detection of deadlocked threads
38) Generate random numbers
39) Java PriorityQueue Example.
40) Java HashSet Example.
41) Java LinkedHashSet Example.
42) Java TreeSet Example.

mardi 24 mars 2015

Servlet avec JSP et JDBC

We have provided a lot of tutorials on servlets in java, this tutorial is aimed to use all of those information to create a full-fledged web application with database connectivity and log4j integration for logging. I strongly recommend to check out following tutorials if you are not familiar with any of these. All of them contains sample project that you can download and run for understanding the core concepts of Servlet API.

Use Case

Develop a web application that should have following features.
  1. User can register and then login to the application.
  2. The users information should be maintained in database.
  3. Use standard logging framework log4j.
  4. The application should support session management, no JSPs should be visible without session. Users can logout anytime from the application.
  5. We should not show application and server details to user incase of any exception in application or other common errors like 404.
Once we have our basic application ready, we can move on to add other features.

Design Decisions

  1. Since login page is the entry point of application, we will have a simple login.html where user can enter their credentials; email and password. We can’t rely on javascript validations, so we will do server side validation and incase of missing information we will redirect user to login page with error details.
  2. We will have a register.html from where user can register to our application, we will provide it’s link in the login page for new user. User should provide email, password, name and country details for registration. If any information is missing, user will remain on same page with error message. If registration is successful, user will be forwarded to the login page with registration success information and they can use email and password to login.
  3. We will use MySql database for persisting user information. We will create a new database, user and Users table for our application. Since our application totally depends on Database Connection, we will create a servlet context listener to initialize the database connection and set it as context attribute for other servlets. We will keep DB configuration details configurable through deployment descriptor. We will also add MySql Java Connector jar to the application libraries.
  4. Since we want to use log4j and configure it properly before usage, we will utilize servlet context listener to configure log4j and keep the log4j configuration XML file location in web.xml init parameters. We will write our application logs in a separate log file dbexample.log for easier debugging.
  5. Incase of any exceptions like “Database Connection Error” or 404 errors, we want to present a useful page to user. We will utilize servlet exception handling and write our own Exception Handler servlet and configure it in deployment descriptor.
  6. Once the user logins successfully, we will create a session for the user and forward them to home.jsp where we will show basic information of the user. We will have a model class User that will store the user data into session. User home page also provide logout button that will invalidate the session and forward them to login page.
  7. We need to make sure all the JSPs and other resources are accessible only when user has a valid session, rather than keeping session validation login in all the resources, we will create a Servlet Filter for session validation and configure it in deployment descriptor.
  8. We will use Servlet 3.0 features for servlet configuration, listeners and filters rather than keeping all of these in deployment descriptor. We will use Eclipse for development and Tomcat 7 for deployment.
Based on above requirements and design decisions, we will create our dynamic web project whose project structure will look like below image.
servlet-example-project-database-log4j
Let’s understand each one of the components and understand their implementation.

Database Setup

We will use below MySql script for new Database, User and Table setup to be used in our application.
MySql_Setup.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
-- login with root to create user, DB and table and provide grants
  
create user 'pankaj'@'localhost' identified by 'pankaj123';
grant all on *.* to 'pankaj'@'localhost' identified by 'pankaj123';
create database UserDB;
use UserDB;
CREATE TABLE `Users` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL DEFAULT '',
  `email` varchar(20) NOT NULL DEFAULT '',
  `country` varchar(20) DEFAULT 'USA',
  `password` varchar(20) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

Login and Registration HTML Pages

Login and Registration HTML pages are simple pages with form to submit the user information, their code looks like below.
login.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html>
<head>
<meta charset="US-ASCII">
<title>Login Page</title>
</head>
<body>
<h3>Login with email and password</h3>
<form action="Login" method="post">
<strong>User Email</strong>:<input type="text" name="email"><br>
<strong>Password</strong>:<input type="password" name="password"><br>
<input type="submit" value="Login">
</form>
<br>
If you are new user, please <a href="register.html">register</a>.
</body>
</html>
register.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html>
<head>
<meta charset="US-ASCII">
<title>Register Page</title>
</head>
<body>
<h3>Provide all the fields for registration.</h3>
<form action="Register" method="post">
<strong>Email ID</strong>:<input type="text" name="email"><br>
<strong>Password</strong>:<input type="password" name="password"><br>
<strong>Name</strong>:<input type="text" name="name"><br>
<strong>Country</strong>:<input type="text" name="country"><br>
<input type="submit" value="Register">
</form>
<br>
If you are registered user, please <a href="login.html">login</a>.
</body>
</html>

Deployment Descriptor and log4j configuration

We will have log4j configuration file inside WEB-INF folder and it will be packaged with the application WAR file.
log4j.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
    debug="false">
    <appender name="dbexample" class="org.apache.log4j.RollingFileAppender">
        <param name="File" value="${catalina.home}/logs/dbexample.log"/>
        <param name="Append"            value="true" />
        <param name="ImmediateFlush"    value="true" />
        <param name="MaxFileSize"       value="20MB" />
        <param name="MaxBackupIndex"    value="10" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%-4r [%t] %-5p %c %x - %m%n" />
        </layout>
    </appender>
     
    <logger name="com.journaldev" additivity="false">
        <level value="DEBUG" />
        <appender-ref ref="dbexample"/>
    </logger>
     
    <root>
        <level value="debug" />
        <appender-ref ref="dbexample" />
    </root>
     
</log4j:configuration>
Our deployment descriptor (web.xml) looks like below.
web.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>ServletDBLog4jExample</display-name>
  <welcome-file-list>
    <welcome-file>login.html</welcome-file>
  </welcome-file-list>
  <context-param>
    <param-name>dbUser</param-name>
    <param-value>pankaj</param-value>
  </context-param>
  <context-param>
    <param-name>dbPassword</param-name>
    <param-value>pankaj123</param-value>
  </context-param>
  <context-param>
    <param-name>dbURL</param-name>
    <param-value>jdbc:mysql://localhost:3306/UserDB</param-value>
  </context-param>
  <context-param>
    <param-name>log4j-config</param-name>
    <param-value>WEB-INF/log4j.xml</param-value>
  </context-param>
   
  <error-page>
    <error-code>404</error-code>
    <location>/AppErrorHandler</location>
  </error-page>
  <error-page>
    <exception-type>java.lang.Throwable</exception-type>
    <location>/AppErrorHandler</location>
  </error-page>
   
  <filter>
    <filter-name>AuthenticationFilter</filter-name>
    <filter-class>com.journaldev.servlet.filters.AuthenticationFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>AuthenticationFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
   
</web-app>
Notice following points in the web.xml configuration.
  1. login.html is provided welcome file in the welcome files list.
  2. Database connection parameters are made configurable and kept as servlet context init params.
  3. log4j configuration file location is also configurable and relative location is provided as context init param.
  4. Our custom exception handler servlet AppErrorHandler is configured to handle all the exceptions thrown by our application code and 404 errors.
  5. AuthenticationFilter is configured to filter all the incoming requests to the application, this is the place where we will have session validation logic.

Model Classes and Database Connection Manager Class

User.java is a simple java bean that will hold the user information as session attribute.
User.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package com.journaldev.util;
import java.io.Serializable;
public class User implements Serializable{
     
    private static final long serialVersionUID = 6297385302078200511L;
     
    private String name;
    private String email;
    private int id;
    private String country;
     
    public User(String nm, String em, String country, int i){
        this.name=nm;
        this.id=i;
        this.country=country;
        this.email=em;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public void setId(int id) {
        this.id = id;
    }
    public void setCountry(String country) {
        this.country = country;
    }
    public String getName() {
        return name;
    }
    public String getEmail() {
        return email;
    }
    public int getId() {
        return id;
    }
    public String getCountry() {
        return country;
    }
     
    @Override
    public String toString(){
        return "Name="+this.name+", Email="+this.email+", Country="+this.country;
    }
}
DBConnectionManager.java is the utility class for MySql database connection and it has a method that returns the connection object. We will use this class for database connection and then set the connection object to servlet context attribute that other servlets can use.
DBConnectionManager.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.journaldev.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBConnectionManager {
    private Connection connection;
     
    public DBConnectionManager(String dbURL, String user, String pwd) throws ClassNotFoundException, SQLException{
        Class.forName("com.mysql.jdbc.Driver");
        this.connection = DriverManager.getConnection(dbURL, user, pwd);
    }
     
    public Connection getConnection(){
        return this.connection;
    }
}

Servlet Context Listener

AppContextListener.java is the servlet context listener implementation that will initialize the Database connection when application context is initialized and it also configures the log4j using it’s configuration xml file. Notice the use of context init params for DB connection and log4j configuration.
When context will be destroyed, we are closing database connection in contextDestroyed() method.
Since we are using Servlet 3, we don’t need to configure it in web.xml and we just need to annotate it with @WebListener annotation.
AppContextListener.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package com.journaldev.servlet.listeners;
import java.io.File;
import java.sql.Connection;
import java.sql.SQLException;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.xml.DOMConfigurator;
import com.journaldev.util.DBConnectionManager;
@WebListener
public class AppContextListener implements ServletContextListener {
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        ServletContext ctx = servletContextEvent.getServletContext();
         
        //initialize DB Connection
        String dbURL = ctx.getInitParameter("dbURL");
        String user = ctx.getInitParameter("dbUser");
        String pwd = ctx.getInitParameter("dbPassword");
         
        try {
            DBConnectionManager connectionManager = new DBConnectionManager(dbURL, user, pwd);
            ctx.setAttribute("DBConnection", connectionManager.getConnection());
            System.out.println("DB Connection initialized successfully.");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
         
        //initialize log4j
        String log4jConfig = ctx.getInitParameter("log4j-config");
        if(log4jConfig == null){
            System.err.println("No log4j-config init param, initializing log4j with BasicConfigurator");
            BasicConfigurator.configure();
        }else {
            String webAppPath = ctx.getRealPath("/");
            String log4jProp = webAppPath + log4jConfig;
            File log4jConfigFile = new File(log4jProp);
            if (log4jConfigFile.exists()) {
                System.out.println("Initializing log4j with: " + log4jProp);
                DOMConfigurator.configure(log4jProp);
            } else {
                System.err.println(log4jProp + " file not found, initializing log4j with BasicConfigurator");
                BasicConfigurator.configure();
            }
        }
        System.out.println("log4j configured properly");
    }
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        Connection con = (Connection) servletContextEvent.getServletContext().getAttribute("DBConnection");
        try {
            con.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
     
}

Exception and Error Handler

AppErrorHandler.java is our application exception handler servlet configured in deployment descriptor, it provides useful information to the user incase of 404 errors or application level exceptions and provide them hyperlink to go to login page of application.
AppErrorHandler.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package com.journaldev.servlet.errorhandler;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/AppErrorHandler")
public class AppErrorHandler extends HttpServlet {
    private static final long serialVersionUID = 1L;
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        processError(request, response);
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        processError(request, response);
    }
     
    private void processError(HttpServletRequest request,
            HttpServletResponse response) throws IOException {
        // Analyze the servlet exception
        Throwable throwable = (Throwable) request
                .getAttribute("javax.servlet.error.exception");
        Integer statusCode = (Integer) request
                .getAttribute("javax.servlet.error.status_code");
        String servletName = (String) request
                .getAttribute("javax.servlet.error.servlet_name");
        if (servletName == null) {
            servletName = "Unknown";
        }
        String requestUri = (String) request
                .getAttribute("javax.servlet.error.request_uri");
        if (requestUri == null) {
            requestUri = "Unknown";
        }
         
        // Set response content type
          response.setContentType("text/html");
      
          PrintWriter out = response.getWriter();
          out.write("<html><head><title>Exception/Error Details</title></head><body>");
          if(statusCode != 500){
              out.write("<h3>Error Details</h3>");
              out.write("<strong>Status Code</strong>:"+statusCode+"<br>");
              out.write("<strong>Requested URI</strong>:"+requestUri);
          }else{
              out.write("<h3>Exception Details</h3>");
              out.write("<ul><li>Servlet Name:"+servletName+"</li>");
              out.write("<li>Exception Name:"+throwable.getClass().getName()+"</li>");
              out.write("<li>Requested URI:"+requestUri+"</li>");
              out.write("<li>Exception Message:"+throwable.getMessage()+"</li>");
              out.write("</ul>");
          }
           
          out.write("<br><br>");
          out.write("<a href=\"login.html\">Login Page</a>");
          out.write("</body></html>");
    }
}

Servlet Filter

AuthenticationFilter.java is our Filter implementation and we are validating user session here.
AuthenticationFilter.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.journaldev.servlet.filters;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.log4j.Logger;
@WebFilter("/AuthenticationFilter")
public class AuthenticationFilter implements Filter {
    private Logger logger = Logger.getLogger(AuthenticationFilter.class);
     
    public void init(FilterConfig fConfig) throws ServletException {
        logger.info("AuthenticationFilter initialized");
    }
     
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
         
        String uri = req.getRequestURI();
        logger.info("Requested Resource::"+uri);
         
        HttpSession session = req.getSession(false);
         
        if(session == null && !(uri.endsWith("html") || uri.endsWith("Login") || uri.endsWith("Register"))){
            logger.error("Unauthorized access request");
            res.sendRedirect("login.html");
        }else{
            // pass the request along the filter chain
            chain.doFilter(request, response);
        }
         
         
    }
    public void destroy() {
        //close any resources here
    }
}
Notice the use of @WebFilter annotation, we can also provide URL Patterns for filter here but sometimes it’s good to have in web.xml to easily disable the filters.

Servlet Classes

LoginServlet resource is used to validate the user input for login and forward them to home page or incase of missing data, provide useful information to user.
LoginServlet.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package com.journaldev.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.log4j.Logger;
import com.journaldev.util.User;
@WebServlet(name = "Login", urlPatterns = { "/Login" })
public class LoginServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    static Logger logger = Logger.getLogger(LoginServlet.class);
     
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String email = request.getParameter("email");
        String password = request.getParameter("password");
        String errorMsg = null;
        if(email == null || email.equals("")){
            errorMsg ="User Email can't be null or empty";
        }
        if(password == null || password.equals("")){
            errorMsg = "Password can't be null or empty";
        }
         
        if(errorMsg != null){
            RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.html");
            PrintWriter out= response.getWriter();
            out.println("<font color=red>"+errorMsg+"</font>");
            rd.include(request, response);
        }else{
         
        Connection con = (Connection) getServletContext().getAttribute("DBConnection");
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            ps = con.prepareStatement("select id, name, email,country from Users where email=? and password=? limit 1");
            ps.setString(1, email);
            ps.setString(2, password);
            rs = ps.executeQuery();
             
            if(rs != null && rs.next()){
                 
                User user = new User(rs.getString("name"), rs.getString("email"), rs.getString("country"), rs.getInt("id"));
                logger.info("User found with details="+user);
                HttpSession session = request.getSession();
                session.setAttribute("User", user);
                response.sendRedirect("home.jsp");;
            }else{
                RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.html");
                PrintWriter out= response.getWriter();
                logger.error("User not found with email="+email);
                out.println("<font color=red>No user found with given email id, please register first.</font>");
                rd.include(request, response);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            logger.error("Database connection problem");
            throw new ServletException("DB Connection problem.");
        }finally{
            try {
                rs.close();
                ps.close();
            } catch (SQLException e) {
                logger.error("SQLException in closing PreparedStatement or ResultSet");;
            }
             
        }
        }
    }
}
LogoutServlet is simple and invalidates the user session and forward them to login page.
LogoutServlet.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.journaldev.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.log4j.Logger;
@WebServlet(name = "Logout", urlPatterns = { "/Logout" })
public class LogoutServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    static Logger logger = Logger.getLogger(LogoutServlet.class);
        
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html");
        Cookie[] cookies = request.getCookies();
        if(cookies != null){
        for(Cookie cookie : cookies){
            if(cookie.getName().equals("JSESSIONID")){
                logger.info("JSESSIONID="+cookie.getValue());
                break;
            }
        }
        }
        //invalidate the session if exists
        HttpSession session = request.getSession(false);
        logger.info("User="+session.getAttribute("User"));
        if(session != null){
            session.invalidate();
        }
        response.sendRedirect("login.html");
    }
}
RegisterServlet is used by users to register to the application and then forward them to login page with registration success message.
RegisterServlet.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package com.journaldev.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
@WebServlet(name = "Register", urlPatterns = { "/Register" })
public class RegisterServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    static Logger logger = Logger.getLogger(RegisterServlet.class);
     
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String email = request.getParameter("email");
        String password = request.getParameter("password");
        String name = request.getParameter("name");
        String country = request.getParameter("country");
        String errorMsg = null;
        if(email == null || email.equals("")){
            errorMsg = "Email ID can't be null or empty.";
        }
        if(password == null || password.equals("")){
            errorMsg = "Password can't be null or empty.";
        }
        if(name == null || name.equals("")){
            errorMsg = "Name can't be null or empty.";
        }
        if(country == null || country.equals("")){
            errorMsg = "Country can't be null or empty.";
        }
         
        if(errorMsg != null){
            RequestDispatcher rd = getServletContext().getRequestDispatcher("/register.html");
            PrintWriter out= response.getWriter();
            out.println("<font color=red>"+errorMsg+"</font>");
            rd.include(request, response);
        }else{
         
        Connection con = (Connection) getServletContext().getAttribute("DBConnection");
        PreparedStatement ps = null;
        try {
            ps = con.prepareStatement("insert into Users(name,email,country, password) values (?,?,?,?)");
            ps.setString(1, name);
            ps.setString(2, email);
            ps.setString(3, country);
            ps.setString(4, password);
             
            ps.execute();
             
            logger.info("User registered with email="+email);
             
            //forward to login page to login
            RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.html");
            PrintWriter out= response.getWriter();
            out.println("<font color=green>Registration successful, please login below.</font>");
            rd.include(request, response);
        } catch (SQLException e) {
            e.printStackTrace();
            logger.error("Database connection problem");
            throw new ServletException("DB Connection problem.");
        }finally{
            try {
                ps.close();
            } catch (SQLException e) {
                logger.error("SQLException in closing PreparedStatement");
            }
        }
        }
         
    }
}

Home JSP Page

home.jsp is the home page for user after successful login, we are just showing some user information here and providing them option to logout.
home.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<%@page import="com.journaldev.util.User"%>
<%@ page language="java" contentType="text/html; charset=US-ASCII"
    pageEncoding="US-ASCII"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Home Page</title>
</head>
<body>
<%User user = (User) session.getAttribute("User"); %>
<h3>Hi <%=user.getName() %></h3>
<strong>Your Email</strong>: <%=user.getEmail() %><br>
<strong>Your Country</strong>: <%=user.getCountry() %><br>
<br>
<form action="Logout" method="post">
<input type="submit" value="Logout" >
</form>
</body>
</html>
The JSP page still contains a lot of java code because we are not using JSP tags, we will look into this in JSP tutorials. As of now please bear with this.

Run the Application

Our application is ready for execution, I would suggest to export it as WAR file and then deploy to tomcat rather than deploying it directly to Tomcat server from Eclipse so that you can easily look into the log4j log file for debugging.
Some sample execution pages are shown in below images.
User Registration Page:
registration-page
Registration Success Page:
registration-success
Login Page:
login-page
User Home Page:
home-page
404 Error Page:
404-error-page
Input Validation Error Page:
input-validation-error-page
log4j Log File:
dbexample.log
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
0    [localhost-startStop-1] INFO  com.journaldev.servlet.filters.AuthenticationFilter  - AuthenticationFilter initialized
1    [localhost-startStop-1] INFO  com.journaldev.servlet.filters.AuthenticationFilter  - AuthenticationFilter initialized
37689 [http-bio-8080-exec-3] INFO  com.journaldev.servlet.filters.AuthenticationFilter  - Requested Resource::/ServletDBLog4jExample/
37689 [http-bio-8080-exec-3] ERROR com.journaldev.servlet.filters.AuthenticationFilter  - Unauthorized access request
37693 [http-bio-8080-exec-4] INFO  com.journaldev.servlet.filters.AuthenticationFilter  - Requested Resource::/ServletDBLog4jExample/login.html
51844 [http-bio-8080-exec-5] INFO  com.journaldev.servlet.filters.AuthenticationFilter  - Requested Resource::/ServletDBLog4jExample/register.html
77818 [http-bio-8080-exec-7] INFO  com.journaldev.servlet.filters.AuthenticationFilter  - Requested Resource::/ServletDBLog4jExample/Login
77835 [http-bio-8080-exec-7] INFO  com.journaldev.servlet.LoginServlet  - User found with details=Name=Pankaj Kumar, Email=pankaj@apple.com, Country=India
77840 [http-bio-8080-exec-8] INFO  com.journaldev.servlet.filters.AuthenticationFilter  - Requested Resource::/ServletDBLog4jExample/home.jsp
98251 [http-bio-8080-exec-9] INFO  com.journaldev.servlet.filters.AuthenticationFilter  - Requested Resource::/ServletDBLog4jExample/Logout
98251 [http-bio-8080-exec-9] INFO  com.journaldev.servlet.LogoutServlet  - JSESSIONID=367DE255789AC02F7C0E0298B825877C
98251 [http-bio-8080-exec-9] INFO  com.journaldev.servlet.LogoutServlet  - User=Name=Pankaj Kumar, Email=pankaj@apple.com, Country=India
98254 [http-bio-8080-exec-10] INFO  com.journaldev.servlet.filters.AuthenticationFilter  - Requested Resource::/ServletDBLog4jExample/login.html
109516 [http-bio-8080-exec-10] INFO  com.journaldev.servlet.filters.AuthenticationFilter  - Requested Resource::/ServletDBLog4jExample/Register
109517 [http-bio-8080-exec-10] INFO  com.journaldev.servlet.RegisterServlet  - User registered with email=abc@abc.com
127848 [http-bio-8080-exec-10] INFO  com.journaldev.servlet.filters.AuthenticationFilter  - Requested Resource::/ServletDBLog4jExample/Login
223055 [http-bio-8080-exec-2] INFO  com.journaldev.servlet.filters.AuthenticationFilter  - Requested Resource::/ServletDBLog4jExample/Login
223056 [http-bio-8080-exec-2] INFO  com.journaldev.servlet.LoginServlet  - User found with details=Name=Pankaj Kumar, Email=pankaj@apple.com, Country=India
223059 [http-bio-8080-exec-2] INFO  com.journaldev.servlet.filters.AuthenticationFilter  - Requested Resource::/ServletDBLog4jExample/home.jsp
231931 [http-bio-8080-exec-2] INFO  com.journaldev.servlet.filters.AuthenticationFilter  - Requested Resource::/ServletDBLog4jExample/invalidurl.jsp

Download Resources