What is a Valve?

A Valve is not defined in the Servlet/JSP spec, it is Tomcat specific. From the Tomcat docs:
A Valve element represents a component that will be inserted into the request processing pipeline for the associated Catalina container (Engine, Host, or Context).

For example, with the valve Remove Address Filter, you can decide whether or not to continue processing the request based on a regular expression that takes as input the IP address of the client.

You associate a Valve with a particular container (Engine, Host, or Context) in server.xml.

Check out the Q/A’s on how to use the Valves that come with Tomcat, and how to write your own.

Writing your own Tomcat Valve

You can extend from org.apache.catalina.valves.ValveBase and implement the method invoke. The following example just prints out is has been called and invokes the next Valve.

MyValve.java:

import javax.servlet.http.*;
import javax.servlet.*;
import java.util.*;
import java.io.*;
import org.apache.catalina.valves.*;
import org.apache.catalina.*;
 
public class MyValve extends ValveBase
{
   /**
    * The descriptive information related to this implementation.
    */
   private static final String info = "MyValve/1.0";
 
   /**
    * Return descriptive information about this Valve implementation.
    */
   public String getInfo() {
      return (info);
   }
 
   public void invoke(Request request, Response response, ValveContext context)
                             throws IOException, ServletException {
      // Skip logging for non-HTTP requests and responses
      if (!(request instanceof HttpRequest) ||
          !(response instanceof HttpResponse)) {
         context.invokeNext(request, response);
         return;
      }
 
      HttpRequest httpRequest   = (HttpRequest) request;
      HttpResponse httpResponse = (HttpResponse) response;
      HttpServletRequest httpServletRequest   = (HttpServletRequest) httpRequest.getRequest();
      HttpServletResponse httpServletResponse = (HttpServletResponse) httpResponse.getResponse();
 
      System.out.println("nnnMyValve invokednnn");
 
      // continue processing the request
      context.invokeNext(request, response);
   }
 
   public String toString() {
      StringBuffer sb = new StringBuffer();
      sb.append("MyValve[");
      if (container != null) {
         sb.append(container);
      }
      sb.append("]");
      return sb.toString();
   }
}

Compile it with catalina.jar and servlet.jar in your classpath and place it in /server/classes.

Retrieving the links in an HTML document

LinkExtractor.java:

package htmltools;
 
import java.net.URL;
import java.net.InetAddress;
import java.net.MalformedURLException;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

import java.util.Collection;
import java.util.ArrayList;

import javax.swing.*;
import javax.swing.text.*;
import javax.swing.text.html.*;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.parser.*;

/**
 * This class takes a URL and, if it is valid, extracts all the external 
 * and local links and stores them in distinct ArrayLists.
 * It provides accessors to the two lists.
 */
public class LinkExtractor
{
    private URL m_zURL = null;
    private CallbackHandler m_zHandler;
    
    /**
     * Initialize the URL. 
     * You can provide URLs in the following form:<br>
     * <font color="blue">
     * http://www.something.ext<br>
     * www.something.ext<br>
     * something.ext<br>
     * </font>
     * In the last case the extractor assumes the URL is on the local
     * host and tries to open it at the local host
     */
    public LinkExtractor(String sURL) throws MalformedURLException, IOException {
	/* End-users don't like typing http, so 
	   we'll give them a hand */
	if (sURL.startsWith("www.")) {
	    sURL = "http://"+sURL;
	} else if (!sURL.startsWith("http")) {
	    /* there is neither an http protocol specified,
	       and the address does not start with www.
	       We will try to find this document on the local host.
	       Of course, this behavior does not cover all cases.
	       For example the user may try an ftp protocol, 
	       or, accostomed to modern day browsers, omit www altogether.
	       Oh well ...
	    */
	    InetAddress zAddr = InetAddress.getLocalHost();
	    sURL = "http://"+zAddr.getHostName()+"/"+sURL;
	}
	
	m_zURL = new URL(sURL);
	m_zHandler = new CallbackHandler();
	parse();
    }

    /**
     * return and ArrayList of all external links
     */
    public Collection getExternalLinks()  {
	if (null == m_zURL)
	    return null;
	return m_zHandler.m_clExternalLinks;    
    }
    
    /**
     * return and ArrayList of all local links
     */ 
    public Collection getLocalLinks()  {
	if (null == m_zURL)
	    return null;
	return m_zHandler.m_clLocalLinks;    
    }
  
  private void parse() throws IOException {
    // establish connection to site
      BufferedReader zReader = new BufferedReader
	  (new InputStreamReader(m_zURL.openStream()));
      // parse it to get the links
      new ParserDelegator().parse(zReader, m_zHandler, true);
      zReader.close();
  }
    
    private class CallbackHandler extends HTMLEditorKit.ParserCallback 
    {
	ArrayList m_clExternalLinks;
	ArrayList m_clLocalLinks;
	
	public CallbackHandler() {
	    
	    m_clExternalLinks = new ArrayList();
	    m_clLocalLinks = new ArrayList();
	}
	
	/**
	 * Invoked when text in the html document is encountered. Based on
	 * the current state, this will either do nothing
	 * or add an href attribute
	 */
	public void handleText(char[] data, int pos) {
	    // System.out.println(new String(data));
	}
	/**
	 * Invoked when a start tag is encountered. 
	 */
	public void handleStartTag(HTML.Tag zTag, 
				   MutableAttributeSet zAttributes,
				   int iPosition) {
	    String sLink = null;
	    
	    if (zTag.equals(HTML.Tag.A) ||
		zTag.equals(HTML.Tag.ADDRESS)) {
		
		sLink = (String)zAttributes.getAttribute(HTML.Attribute.HREF);
		if (null == sLink) { 
		    
		} else if (sLink.startsWith("http")) {
		    if (!m_clExternalLinks.contains((String)sLink)) {
			m_clExternalLinks.add((String)sLink);
		    }
		} else if (!m_clLocalLinks.contains((String)sLink)) {
		    m_clLocalLinks.add((String)sLink);
		} 
	    }
	}
	
	
	/**
	 * Invoked when the end of a tag is encountered. 
	 */
	public void handleEndTag(HTML.Tag t, int pos) {
	    
	}	    
   }

    /*
     * The main method is provided only for testing.
     */
    static void main(String[] asArgs) throws Exception {
	if (asArgs.length < 1) {
	    System.out.println("Usage: java GetLinks <URL>");
	    System.exit(0);
	}
	String sURL = asArgs[0];

	LinkExtractor gl = new LinkExtractor(sURL);
	ArrayList clLinks = (ArrayList) gl.getExternalLinks();
	
	for (int i=0;i<clLinks.size();i++) {
	    System.out.println((String)clLinks.get(i));
	}
	
	ArrayList clLocalLinks = (ArrayList) gl.getLocalLinks();	
	for (int i=0;i<clLocalLinks.size();i++) {
	    System.out.println((String)clLocalLinks.get(i));
	}
    }
}

Getting the list of network interfaces installed on your machine

If you have multiple IP addresses on one machine, it may be useful to specify which one to use for your networking stuff. Since JDK1.4, you can enumerate them and select one with the class java.net.NetworkInterface.

Main.java:

import java.util.*;
import java.net.*;
 
public class Main
{
   public static void main(String []args) {
      try {
         Enumeration enum = NetworkInterface.getNetworkInterfaces();
         while (enum.hasMoreElements()) {
            NetworkInterface ni = (NetworkInterface) enum.nextElement();
            System.out.println(ni);
         }
      }
      catch(SocketException e) {
         e.printStackTrace();
      }
   }
}

outputs on my Win2000 machine:

name:lan0 (Intel DC21140 PCI Fast Ethernet Adapter) index: 1 addresses:
/192.168.2.10;

name:lan1 (Intel DC21140 PCI Fast Ethernet Adapter) index: 2 addresses:

name:lo0 (MS TCP Loopback interface) index: 3 addresses:
/127.0.0.1;

Performance gain of using NIO channels as opposed to regular streams for doing file I/O

To test things out, I wrote a couple small Java programs to copy a file:

CopyFile1.java: uses the old approach using BufferedInput/BufferedOutputStreams with the default buffer size of 2048 bytes
CopyFile2.java: uses the NIO libraries with different buffer sizes
CopyFile3.java: uses the NIO FileChannel method transferTo

CopyFile1.java uses BufferedInputStream and BufferedOutputStream. If you look at the source code for these files, the default buffer is an array of 2048 bytes. The first version of the NIO CopyFile2 program is also set to use an internal buffer of 2048 bytes. Other tests have been done with larger buffer sizes. As expected, the more buffer space allocated, the higher the performance (at a cost of more memory usage).

The result of copying the Java SDK file j2sdk-1_4_0-win.exe(37Meg) using JDK1.2.2, JDK1.3 and JDK1.4 on a Win2000/450Mhz machine is plotted here:


(All numbers are seconds)

CopyFile1.java:

import java.io.*;
 
public class CopyFile1
{
   public static void main(String []args) throws IOException {
      if (args.length != 2) {
         System.err.println("Usage: java CopyFile1 source dest");
         System.exit(1);
      }
 
      String source = args[0];
      String dest = args[1];
 
      long start = System.currentTimeMillis();
 
      BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source));
      BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest));
 
      int k;
      while ((k = bis.read()) != -1) {
         bos.write(k);
      }
   
      bis.close();
      bos.close();
 
      long stop = System.currentTimeMillis();
 
      System.out.println("Total time it took to copy: " + (stop - start) + "ms.");
   }
}

CopyFile2.java:

import java.nio.*;
import java.nio.channels.*;
import java.io.*;
 
public class CopyFile2
{
   public static void main(String []args) throws IOException {
      if (args.length != 2) {
         System.err.println("Usage: java CopyFile2 source dest");
         System.exit(1);
      }
 
      String source = args[0];
      String dest = args[1];
 
      long start = System.currentTimeMillis();
 
      FileInputStream fis = new FileInputStream(source);
      FileOutputStream fos = new FileOutputStream(dest);
      
      FileChannel channelIn = fis.getChannel();
      FileChannel channelOut = fos.getChannel();
 
      ByteBuffer buffer = ByteBuffer.allocateDirect(2048); 
 
      int n = channelIn.read(buffer);
      while (n > -1) {
         buffer.flip();
         channelOut.write(buffer);
         buffer.clear();
  
         n = channelIn.read(buffer);
      }      
 
      long stop = System.currentTimeMillis();
 
      System.out.println("Total time it took to copy: " + (stop - start) + "ms.");
   }
}

CopyFile3.java:

import java.nio.*;    
import java.nio.channels.*;    
import java.io.*;        
 
public class CopyFile3 
{        
   public static void main(String args[]) throws IOException {                
      if (args.length != 2) {
         System.err.println("Usage: java CopyFile3 source dest");
         System.exit(1);
      }             
 
      String source = args[0];
      String dest = args[1];
 
      long start = System.currentTimeMillis();
 
      FileInputStream fis = new FileInputStream(source);            
      FileOutputStream fos = new FileOutputStream(dest);            
      
      FileChannel channelIn = fis.getChannel();
      FileChannel channelOut = fos.getChannel();
 
      channelIn.transferTo(0, channelIn.size(), channelOut);                
 
      channelIn.close();            
      channelOut.close();            
 
      long stop = System.currentTimeMillis();
 
      System.out.println("Total time it took to copy: " + (stop - start) + "ms.");
   }    
}

Native byte order on your machine

Simple, in JDK1.4+, use java.nio.ByteOrder.nativeOrder()

Main.java:

import java.nio.*;
 
public class Main
{
   public static void main(String []args) {
      ByteOrder bo = ByteOrder.nativeOrder();
      
      System.out.println("Native byte order of your platform is " + bo);
   }
}

outputs on my win machine:

Native byte order of your platform is LITTLE_ENDIAN

What is an NIO Buffer?

A buffer is used to transfer data between channels.

Internal state

Internally, a buffer is an array of data, where the type is determined by the subclass of java.nio.Buffer that is used: ShortBuffer, IntBuffer, FloatBuffer, DoubleBuffer, LongBuffer, CharBuffer and ByteBuffer.

A buffer maintains three essential properties: capacity, limit and position. Look at the example below for how these properties behave.

  • capacity: is the number of elements the buffer can contain. Once a buffer is allocated, its capacity never changes.

  • limit: the index of the first element that should not be read or written. In other words, elements are usable and can be read up to the index limit-1. For writing, the limit is typically equal to the capacity of the Buffer.
  • position: the index of the next element to be read or written. It is never greater than the limit.

    Creating Buffers

    You can’t directly create Buffers using a constructor.

    Example:

       // allocates memory that can contain 128 bytes
       ByteBuffer byteBuffer = ByteBuffer.allocate(128);
       // prints out 128
       System.out.println(byteBuffer.capacity());
     
       // allocates memory that can contain 128 integers
       IntBuffer intBuffer = IntBuffer.allocate(128);
       // prints out 128
       System.out.println(intBuffer.capacity());
    
  • You can also create a view on an existing ByteBuffer. The two buffers, the original and the view will operate on the same memory, so changing in one buffer will have direct effect in the other one.

    Example:

       // allocates memory that can contain 128 bytes
       ByteBuffer byteBuffer = ByteBuffer.allocate(128);
       // prints out 128
       System.out.println(byteBuffer.capacity());
    
       // Create an intBuffer view on the byteBuffer
       IntBuffer intBuffer = byteBuffer.asIntBuffer();
       // prints out 32, because 128 bytes is 32 integers of 4 bytes each
       System.out.println(intBuffer.capacity());
    
  • To create a Buffer from an existing array, use the wrap method. Changing the original array will change the Buffer.

    WrapExample.java:

    import java.nio.*;
     
    public class WrapExample
    {
       public static void main(String []args) {
          long la[] = { 10, 20, 30, 40 };  
          LongBuffer lb = LongBuffer.wrap(la);
     
          System.out.println("LongBuffer before changing original array");
          printBuffer(lb);
     
          // change the original array
          la[2] = 123456;
     
          System.out.println("LongBuffer after changing original array");
          printBuffer(lb);
       }
       
       public static void printBuffer(LongBuffer lb) {
          for (int i=0; i<lb.limit(); i++) {
             System.out.print(lb.get(i) + " ");
          }
          System.out.println();
       }
    }
    

    Reading/writing from and to a Buffer

    To read and write values from a buffer, you use that buffer’s specific get and put methods, that you can use in relative or absolute mode.

    The following example creates a CharBuffer and writes data to it.

    CharBufferTest.java:

    import java.nio.*;
     
    public class CharBufferTest 
    {
       public static void main(String []args) {
          CharBuffer cb = CharBuffer.allocate(10);
     
          cb.put('a'); 	// use relative put
          cb.put(3, 'b');	// use absolute put
          cb.put('c');	// use relative put
    
          printBuffer(cb);
       }
      
       public static void printBuffer(CharBuffer cb) {
          for (int i=0; i<cb.limit(); i++) {
             System.out.print(cb.get(i) + " ");
          }
          System.out.println();
       }
    } 
    

    outputs:

    a c   b
    

    Buffer Operations

    • flip(): Sets the limit to the current position and the position to zero. This method is typically used after a channel-read (put-operations in Buffer terms) and before a channel-write (get-operations in Buffer terms).

    Example buffer:
     
                          position     limit
                             |           |
           +---+---+---+---+---+---+---+
           | 2 | 4 | 3 | 9 | 0 | 0 | 0 |
           +---+---+---+---+---+---+---+
     
    After flip():
     
          position         limit
             |               |
           +---+---+---+---+---+---+---+
           | 2 | 4 | 3 | 9 | 0 | 0 | 0 |
           +---+---+---+---+---+---+---+
     
    Typical usage:
     
       inChannel.read(buffer);      // transfers data from the channel to the buffer
       flip();                      // prepares buffer for relative get-operations
       outChannel.write(buffer);    // transfers data from the buffer to the channel
    
  • clear(): Sets the limit to the Buffer’s capacity and the position to zero. This method is typically used after a channel-write (get-operations in Buffer terms) and before a channel-read (put-operations in Buffer terms).
    Example buffer that was just used by an out channel:
     
                          position
                           limit
                             |
           +---+---+---+---+---+---+---+
           | 2 | 4 | 3 | 9 | 0 | 0 | 0 |
           +---+---+---+---+---+---+---+
     
    After clear():
     
         position                      limit
             |                           |
           +---+---+---+---+---+---+---+
           | 2 | 4 | 3 | 9 | 0 | 0 | 0 |
           +---+---+---+---+---+---+---+
      
    Typical usage:
      
       outChannel.write(buffer);    // transfers data from the buffer to the channel
       clear();                     // prepares buffer for relative put-operations
       inChannel.read(buffer);      // transfers data from the channel to the buffer
    
  • rewind(): Sets the position to zero
  • position(int): with this method, you can assign a new index to the position. If the position is larger than the current limit, an IllegalArgumentException is thrown.
  • limit(int): with this method, you can assign a new index to the limit. The position is set to this limit if it is larger (the position is never larger than the limit).

    Here is an example of the different operations.

    Main.java:

    import java.nio.*;
     
    public class Main
    {
       public static void main(String []args) {
          ByteBuffer bb = ByteBuffer.allocate(10);
     
          printVars("Initial state", bb);
     
          bb.put((byte) 1);
          printVars("bb.put((byte) 1)", bb);
     
          bb.putFloat(3.4f);
          printVars("bb.putFloat(3.4f)", bb);
     
          bb.flip();
          printVars("flip()", bb);
     
          bb.put((byte) 2);
          printVars("bb.put((byte) 2)", bb);
     
          bb.position(5);
          printVars("bb.position(5)", bb);
     
          bb.clear();
          printVars("clear()", bb);
       }
     
       public static void printVars(String state, ByteBuffer bb) {
          System.out.println(state);
          printTag("limit", bb.limit());
          printTag("position", bb.position());
          printLine(bb);
          System.out.print("t| ");
          for (int i=0; i<bb.capacity(); i++) {
             String hexValue = getHexValue(bb, i);
             System.out.print(" " + hexValue.toUpperCase() + " | ");
          }
          System.out.println();
          printLine(bb);
          System.out.println("tCapacity: " + bb.capacity() + 
                             ", remaining: " + bb.remaining());
          System.out.println();
       }
     
       public static void printLine(ByteBuffer bb) {
          System.out.print("t+");
          for (int i=0; i<bb.capacity(); i++) {
             System.out.print("-----+");
          }
          System.out.println();
       }
     
       public static void printTag(String tag, int pos) {
          System.out.print("t   ");
          for (int i=0; i<pos; i++) {
             System.out.print("      ");
          }
          System.out.println(tag);
          System.out.print("t   ");
          for (int i=0; i<pos; i++) {
             System.out.print("      ");
          }
          System.out.println("|");
       }
     
       public static String getHexValue(ByteBuffer bb, int pos) {
          String hexValue = "??";
          if (pos >= bb.limit()) {
             hexValue = "??";
          }
          else {
             hexValue = Integer.toHexString(bb.get(pos));
          }
          if (hexValue.length() > 2) {
             hexValue = hexValue.substring(hexValue.length()-2);
          }
          else if (hexValue.length() == 1) {
             hexValue = "0" + hexValue;
          }
          return hexValue;
       }
    }
    

    outputs:

    Initial state
    	                                                               limit
    	                                                               |
    	   position
    	   |
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	|  00 |  00 |  00 |  00 |  00 |  00 |  00 |  00 |  00 |  00 | 
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	Capacity: 10, remaining: 10
     
    bb.put((byte) 1)
    	                                                               limit
    	                                                               |
    	         position
    	         |
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	|  01 |  00 |  00 |  00 |  00 |  00 |  00 |  00 |  00 |  00 | 
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	Capacity: 10, remaining: 9
     
    bb.putFloat(3.4f)
    	                                                               limit
    	                                                               |
    	                                 position
    	                                 |
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	|  01 |  40 |  59 |  99 |  9A |  00 |  00 |  00 |  00 |  00 | 
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	Capacity: 10, remaining: 5
     
    flip()
    	                                 limit
    	                                 |
    	   position
    	   |
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	|  01 |  40 |  59 |  99 |  9A |  ?? |  ?? |  ?? |  ?? |  ?? | 
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	Capacity: 10, remaining: 5
     
    bb.put((byte) 2)
    	                                 limit
    	                                 |
    	         position
    	         |
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	|  02 |  40 |  59 |  99 |  9A |  ?? |  ?? |  ?? |  ?? |  ?? | 
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	Capacity: 10, remaining: 4
     
    bb.position(5)
    	                                 limit
    	                                 |
    	                                 position
    	                                 |
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	|  02 |  40 |  59 |  99 |  9A |  ?? |  ?? |  ?? |  ?? |  ?? | 
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	Capacity: 10, remaining: 0
     
    clear()
    	                                                               limit
    	                                                               |
    	   position
    	   |
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	|  02 |  40 |  59 |  99 |  9A |  00 |  00 |  00 |  00 |  00 | 
    	+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
    	Capacity: 10, remaining: 10
    

  • In NIO, what is the difference between a mandatory lock and an advisory lock?

    A lock makes it possible to lock an entire file or a region of a file. Some filesystems implement advisory locking, which means that programs must all work together in order to preserve file integrity. It’s similar to having a synchronized block, which doesn’t really prevent your data from being corrupted, but just prevents threads to acquire the same lock.
    If mandatory locking is implemented in a filesystem, a process cannot access a file or a region on a file in a way that would violate the lock.

    Configuring Tomcat to use SSL

    SSL stands for Secure Socket Layer. It allows the communication between your browser and the webserver to be encrypted. Tomcat is a Servlet/JSP container but is just a simple webserver as well. Typically, the Apache web server is used to serve static pages while the servlet/JSP requests are redirected to the Tomcat container. Then you can simply configure SSL on the Apache Web server level, in which case you would not need to do SSL configuration on Tomcat itself. It is useful however if you are running Tomcat standalone.

    1) Install JSSE

    If you are not using JDK1.4+, you need to install JSSE separately. I was using JDK1.3.1 to create this example, and to make it easy, I copied to files jcert.jar, jnet.jar, jsse.jar into c:\jdk1.3.1\jre\lib\ext. If you do this, you don’t need to fiddle around with the classpath. You can d/l JSSE here: http://java.sun.com/products/jsse/.

    2) Create a keystore file that contains your certificate:

    C:\Program Files\Apache Tomcat 4.0>keytool -genkey -alias tomcat -keyalg RSA 
                                               -keystore tomcatkeystore.kst
    Enter keystore password:  123456
    What is your first and last name?
      [Unknown]:  Joris Van den Bogaert
    What is the name of your organizational unit?
      [Unknown]:  Esus
    What is the name of your organization?
      [Unknown]:  Esus
    What is the name of your City or Locality?
      [Unknown]:  Brussels
    What is the name of your State or Province?
      [Unknown]:
    What is the two-letter country code for this unit?
      [Unknown]:  BE
    Is <CN=Joris Van den Bogaert, OU=Esus, O=Esus, L=Brussels, ST=Unknown, C=BE> correct?
      [no]:  yes
     
    Enter key password for <tomcat>
            (RETURN if same as keystore password):  123456
    

    3) Modify TOMCAT-HOME/bin/server.xml

    You can just uncomment the SSL connector. Modify it so that it points to the keystore file that you just created:

        <!-- Define an SSL HTTP/1.1 Connector on port 8443 -->
        <Connector className="org.apache.catalina.connector.http.HttpConnector"
                   port="8443" minProcessors="5" maxProcessors="75"
                   enableLookups="true"
    	       acceptCount="10" debug="0" scheme="https" secure="true">
          <Factory className="org.apache.catalina.net.SSLServerSocketFactory"
                   clientAuth="false" protocol="TLS"
                   keystoreFile="tomcatkeystore.kst" 
                   keystorePass="123456"/>
        </Connector>
    

    Note 1: 8443 is the port number that Tomcat will listen to for secure connections. If you want
    to use another port number, make sure you also change the redirectPort attribute in the non-SSL connector to point to the port you choose.

    Note 2: If you didn’t specify the option -keystore when creating your certificate, the keystore would have been stored in your home directory as .keystore. In that case, you don’t need to specify the keystoreFile nor keystorePass.

    4) Restart Tomcat

    5) Check it out: https://localhost:8443

    Changing the default session timeout with Tomcat

    You can specify the session timeout in your web.xml deployment descriptor. The <session-timeout%gt; tag specifies the number of minutes of inactivity that the container will allow before the HttpSession object becomes invalid.

    eg.

        <session-config>
            <session-timeout>
                30
            </session-timeout>
        </session-config>
    

    You can also set your own timeout interval in your servlet or jsp:

    <html>
    <body>
    <% 
       session.setMaxInactiveInterval(30);
    %>
    </body>
    </html>