« The Christmas Story attacked by Newsweek | Main | Blog Spam! »

December 17, 2004

How to Embed Tomcat 5.5.x (really, it works!)

Some of you out there may be wondering, how do I embed Tomcat 5.5.x into my application? My 5.0.x code no longer works in the 5.5.x line. There has been some api changes in the Embedded class along with a bug in the Embedded.createConnector(...) method see (here) After fiddling with the Catalina classes around all morning, I have been able to get the the Embedded Tomcat to work so here is the code.

 

Note: This is using the Tomcat 5.5.4 embed version.
import java.io.File;
import java.net.InetAddress;

import org.apache.catalina.Context;
import org.apache.catalina.Engine;
import org.apache.catalina.Host;
import org.apache.catalina.Session;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.realm.MemoryRealm;
import org.apache.catalina.startup.Embedded;
import org.apache.tomcat.util.IntrospectionUtils;

/**
 * @author placson
 */
public class Tomcat55 {

    private String path = null;
    private Embedded embedded = null;
    private Host host = null;
    private Context rootcontext;
    public Tomcat55() {
    }

    /**
     * Set Session scope variable
     * 
     * @param name
     *            Session variable name
     * @param obj
     *            Session variable value
     */
    public void setRootContextSessionAttribute(String name, Object obj) {
        try {
            Session sessions[] = this.rootcontext.getManager().findSessions();

            for (int i = 0, size = sessions.length; i < size; i++) {
                sessions[i].getSession().setAttribute(name, obj);
            }
        } catch (Exception x) {
        }
    }

    /**
     * Get Application scope variable
     * 
     * @param name
     *            Application variable name
     * @return Application variable value
     */
    public Object getRootContextAttribute(String name) {
        return this.rootcontext.getServletContext().getAttribute(name);
    }

    /**
     * Set Application scope variable
     * 
     * @param name
     *            Application variable name
     * @param obj
     *            Application variable value
     */
    public void setRootContextAttribute(String name, Object obj) {
        this.rootcontext.getServletContext().setAttribute(name, obj);
    }

    /**
     * Remove Application scope variable
     * 
     * @param name
     *            Application variable name
     */
    public void removeRootContextAttribute(String name) {
        this.rootcontext.getServletContext().removeAttribute(name);
    }

    /**
     * Basic Accessor setting the value of the context path
     * 
     * @param path -
     *            the path
     */
    public void setPath(String path) {

        this.path = path;
    }

    /**
     * Basic Accessor returning the value of the context path
     * 
     * @return - the context path
     */
    public String getPath() {
        return this.path;
    }

    /**
     * This method Starts the Tomcat server.
     */
    public void startTomcat() throws Exception {
        Engine engine = null;

        // Create an embedded server
        this.embedded = new Embedded();
        this.embedded.setCatalinaHome(getPath());

        // set the memory realm
        MemoryRealm memRealm = new MemoryRealm();
        this.embedded.setRealm(memRealm);

        // Create an engine
        engine = this.embedded.createEngine();
        engine.setDefaultHost("localhost");

        // Create a default virtual host
        this.host = this.embedded.createHost("localhost", getPath()
                + "/webapps");
        engine.addChild(this.host);


        // Create the ROOT context
        this.rootcontext = this.embedded.createContext("", getPath()
                + "/webapps/ROOT");
        this.rootcontext.setReloadable(false);
        this.rootcontext.addWelcomeFile("index.jsp");
        this.host.addChild(this.rootcontext);

        // create another application Context
        Context appCtx = this.embedded.createContext("/manager", getPath() + "/webapps/manager");
        appCtx.setPrivileged(true); 
        this.host.addChild(appCtx); // add context to host

        

        // Install the assembled container hierarchy
        this.embedded.addEngine(engine);

        int port = 8080;
        String addr = null;
        Connector connector = null;//this.embedded.createConnector(addr, port, false);
        /*
         * embedded.createConnector(...)
         * seems to be broken.. it always returns a null connector.
         * see work around below
         */
        InetAddress address = null;
        try {
            connector = new Connector();
            //httpConnector.setScheme("http");
            connector.setSecure(false);
            address = InetAddress.getLocalHost();
            if (address != null) {
                IntrospectionUtils.setProperty(connector, "address", ""
                        + address);
            }
            IntrospectionUtils.setProperty(connector, "port", "" + port);
            
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        connector.setEnableLookups(false);

        this.embedded.addConnector(connector);
        // Start the embedded server
        this.embedded.start();
    }

    /**
     * Refresh ROOT context
     *  
     */
    public void reloadRoot() {
        this.rootcontext.reload();
    }

    /**
     * Remove ROOT context
     *  
     */
    public void removeRoot() {
        this.host.removeChild(this.rootcontext);
    }

    /**
     * Add ROOT context
     *  
     */
    public void addRoot() {
        this.host.addChild(this.rootcontext);
    }

    /**
     * This method Stops the Tomcat server.
     */
    public void stopTomcat() throws Exception {
        // Stop the embedded server
        this.embedded.stop();
    }

    /**
     * Registers a WAR with the container.
     * 
     * @param contextPath -
     *            the context path under which the application will be
     *            registered
     * @param warFile -
     *            the URL of the WAR to be registered.
     */
    public void registerWAR(String contextPath, String absolutePath)
            throws Exception {
        Context context = this.embedded
                .createContext(contextPath, absolutePath);
        context.setReloadable(false);
        this.host.addChild(context);
    }

    /**
     * Unregisters a WAR from the web server.
     * 
     * @param contextPath -
     *            the context path to be removed
     */
    public void unregisterWAR(String contextPath) throws Exception {

        Context context = this.host.map(contextPath);
        if (context != null) {
            this.embedded.removeContext(context);
        } else {
            throw new Exception("Context does not exist for named path : "
                    + contextPath);
        }
    }

    
    public static void main(String[] args) {
        Tomcat55 tomcat = new Tomcat55();
        /* jdk15 verify */ 
        java.util.LinkedList<Integer> list = new java.util.LinkedList<Integer>();
        tomcat.setPath(new File(".").getAbsolutePath());
        try {
            tomcat.startTomcat();
            
            // unload root after 5 seconds
            Thread.currentThread().sleep(5*1000);
            tomcat.removeRoot();
            System.out.println("Root context removed!");

            // wait another 5 seconds and add again
            Thread.currentThread().sleep(5*1000);
            tomcat.addRoot();
            System.out.println("Root context added!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Posted by patrick at December 17, 2004 11:40 AM

Comments

Post a comment




Remember Me?

(you may use HTML tags for style)