Dipak Prajapati
Dipak Prajapati

Reputation: 528

Add tomcat listener LifecycleListener without changing server.xml or tomcat/web.xml

I have below code which required below entry in server.xml and file must placed in tomcat/lib.

I want to add tomcat listener and do not want to make any changes in tomcat server configuration. Is there any way I can achieve this?

Note : I have already tried "ServletContextListener" but it is not accurate as LifecycleListener.

Server.xml

<Listener className="com.tomcat.listener.TomcatListener"/>

Java file

package com.tomcat.listener;

import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;

public class TomcatListener implements LifecycleListener {
    @Override
    public void lifecycleEvent(LifecycleEvent event) {
        if(Lifecycle.AFTER_START_EVENT.equals(event.getType())){
            System.out.print("Tomcat successfully started");
        }
    }
}

Upvotes: 1

Views: 1663

Answers (1)

Dipak Prajapati
Dipak Prajapati

Reputation: 528

With the help of ServletContextListener, LifecycleListener and reflection I am able to achieve what I was expecting.

So here we are first capturing event of ServletContextListener to get the ServletContext and then using reflection and we are accessing private fields to add listener in ServletContext implementation of Tomcat

CustomServletListener.java

import org.apache.catalina.core.ApplicationContext;
import org.apache.catalina.core.ApplicationContextFacade;
import org.apache.catalina.core.StandardContext;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.lang.reflect.Field;

public final class CustomServletListener implements ServletContextListener {
    @Override
    public void contextDestroyed(ServletContextEvent event) {
    }

    @Override
    public void contextInitialized(ServletContextEvent event) {
        addLifeCycleListener(event);
    }

    /**
     * Tomcat Implementation of ServletContext in ApplicationContextFacade, ApplicationContext,StandardContext as to addListener is located in StandardContext 
     * @param event
     */
    private void addLifeCycleListener(ServletContextEvent event) {
        ApplicationContextFacade source = (ApplicationContextFacade) event.getSource();
        ApplicationContext objApplicationContext=get(source, "context");
        StandardContext objStandardContext = get(objApplicationContext, "context");
        objStandardContext.addLifecycleListener(new TomcatListener());
    }

    /**
     * Get class field using reflection as it is no way to direct access
     * @param object
     * @param fieldName
     * @param <V>
     * @return
     */
    @SuppressWarnings("unchecked")
    private <V> V get(Object object, String fieldName) {
        Class<?> clazz = object.getClass();
        Field field = null;
        boolean wasAccessible = false;
        while (clazz != null) {
            try {
                field = clazz.getDeclaredField(fieldName);
                wasAccessible = field.isAccessible();
                if (!wasAccessible) {
                    field.setAccessible(true);
                }
                return (V) field.get(object);
            } catch (NoSuchFieldException e) {
                clazz = clazz.getSuperclass();
            } catch (IllegalAccessException e) {
                throw new IllegalStateException(e);
            } finally {
                // Revert the Accessibility flag to previous state
                if(null != field && field.isAccessible() != wasAccessible){
                    field.setAccessible(wasAccessible); 
                }
            }
        }
        return null;
    }
}

TomcatListener.java

import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;

public class TomcatListener implements LifecycleListener {
    @Override
    public void lifecycleEvent(LifecycleEvent event) {
        if (Lifecycle.AFTER_START_EVENT.equals(event.getType())) {
            System.out.print("Tomcat successfully started");
        }
    }
}

Upvotes: 2

Related Questions