net.lightbody.bmp.proxy.jetty.jetty.servlet.ServletHolder.java Source code

Java tutorial

Introduction

Here is the source code for net.lightbody.bmp.proxy.jetty.jetty.servlet.ServletHolder.java

Source

// ========================================================================
// $Id: ServletHolder.java,v 1.53 2005/11/03 08:52:48 gregwilkins Exp $
// Copyright 199-2004 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at 
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================

package net.lightbody.bmp.proxy.jetty.jetty.servlet;

import net.lightbody.bmp.proxy.jetty.http.HttpRequest;
import net.lightbody.bmp.proxy.jetty.http.UserRealm;
import net.lightbody.bmp.proxy.jetty.log.LogFactory;
import org.apache.commons.logging.Log;

import javax.servlet.*;
import java.io.IOException;
import java.security.Principal;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

/* --------------------------------------------------------------------- */
/** Servlet Instance and Context Holder.
 * Holds the name, params and some state of a javax.servlet.Servlet
 * instance. It implements the ServletConfig interface.
 * This class will organise the loading of the servlet when needed or
 * requested.
 *
 * @version $Id: ServletHolder.java,v 1.53 2005/11/03 08:52:48 gregwilkins Exp $
 * @author Greg Wilkins
 */
public class ServletHolder extends Holder implements Comparable {
    private static Log log = LogFactory.getLog(ServletHolder.class);

    /* ---------------------------------------------------------------- */

    private int _initOrder;
    private boolean _initOnStartup = false;
    private Map _roleMap;
    private String _forcedPath;
    private String _runAs;
    private UserRealm _realm;

    private transient Stack _servlets;
    private transient Servlet _servlet;
    private transient Config _config;
    private transient long _unavailable;
    private transient UnavailableException _unavailableEx;

    /* ---------------------------------------------------------------- */
    /** Constructor for Serialization.
     */
    public ServletHolder() {
    }

    /* ---------------------------------------------------------------- */
    /** Constructor.
     * @param handler The ServletHandler instance for this servlet.
     * @param name The name of the servlet.
     * @param className The class name of the servlet.
     */
    public ServletHolder(ServletHandler handler, String name, String className) {
        super(handler, (name == null) ? className : name, className);
    }

    /* ---------------------------------------------------------------- */
    /** Constructor. 
     * @param handler The ServletHandler instance for this servlet.
     * @param name The name of the servlet.
     * @param className The class name of the servlet.
     * @param forcedPath If non null, the request attribute
     * javax.servlet.include.servlet_path will be set to this path before
     * service is called.
     */
    public ServletHolder(ServletHandler handler, String name, String className, String forcedPath) {
        this(handler, (name == null) ? className : name, className);
        _forcedPath = forcedPath;
    }

    /* ------------------------------------------------------------ */
    public int getInitOrder() {
        return _initOrder;
    }

    /* ------------------------------------------------------------ */
    /** Set the initialize order.
     * Holders with order<0, are initialized on use. Those with
     * order>=0 are initialized in increasing order when the handler
     * is started.
     */
    public void setInitOrder(int order) {
        _initOnStartup = true;
        _initOrder = order;
    }

    /* ------------------------------------------------------------ */
    /** Comparitor by init order.
     */
    public int compareTo(Object o) {
        if (o instanceof ServletHolder) {
            ServletHolder sh = (ServletHolder) o;
            if (sh == this)
                return 0;
            if (sh._initOrder < _initOrder)
                return 1;
            if (sh._initOrder > _initOrder)
                return -1;
            int c = _className.compareTo(sh._className);
            if (c == 0)
                c = _name.compareTo(sh._name);
            if (c == 0)
                c = this.hashCode() > o.hashCode() ? 1 : -1;
            return c;
        }
        return 1;
    }

    /* ------------------------------------------------------------ */
    public boolean equals(Object o) {
        return compareTo(o) == 0;
    }

    /* ------------------------------------------------------------ */
    public int hashCode() {
        return _name.hashCode();
    }

    /* ---------------------------------------------------------------- */
    public ServletContext getServletContext() {
        return ((ServletHandler) _httpHandler).getServletContext();
    }

    /* ------------------------------------------------------------ */
    /** Link a user role.
     * Translate the role name used by a servlet, to the link name
     * used by the container.
     * @param name The role name as used by the servlet
     * @param link The role name as used by the container.
     */
    public synchronized void setUserRoleLink(String name, String link) {
        if (_roleMap == null)
            _roleMap = new HashMap();
        _roleMap.put(name, link);
    }

    /* ------------------------------------------------------------ */
    /** get a user role link.
     * @param name The name of the role
     * @return The name as translated by the link. If no link exists,
     * the name is returned.
     */
    public String getUserRoleLink(String name) {
        if (_roleMap == null)
            return name;
        String link = (String) _roleMap.get(name);
        return (link == null) ? name : link;
    }

    /* ------------------------------------------------------------ */
    /** 
     * @param role Role name that is added to UserPrincipal when this servlet
     * is called. 
     */
    public void setRunAs(String role) {
        _runAs = role;
    }

    /* ------------------------------------------------------------ */
    public String getRunAs() {
        return _runAs;
    }

    /* ------------------------------------------------------------ */
    public void start() throws Exception {
        _unavailable = 0;
        super.start();

        if (!javax.servlet.Servlet.class.isAssignableFrom(_class)) {
            Exception ex = new IllegalStateException("Servlet " + _class + " is not a javax.servlet.Servlet");
            super.stop();
            throw ex;
        }

        _config = new Config();
        if (_runAs != null)
            _realm = _httpHandler.getHttpContext().getRealm();

        if (javax.servlet.SingleThreadModel.class.isAssignableFrom(_class))
            _servlets = new Stack();

        if (_initOnStartup) {
            _servlet = (Servlet) newInstance();
            try {
                initServlet(_servlet, _config);
            } catch (Throwable e) {
                _servlet = null;
                _config = null;
                if (e instanceof Exception)
                    throw (Exception) e;
                else if (e instanceof Error)
                    throw (Error) e;
                else
                    throw new ServletException(e);
            }
        }
    }

    /* ------------------------------------------------------------ */
    public void stop() {
        Principal user = null;
        try {
            // Handle run as
            if (_runAs != null && _realm != null)
                user = _realm.pushRole(null, _runAs);

            if (_servlet != null)
                _servlet.destroy();
            _servlet = null;

            while (_servlets != null && _servlets.size() > 0) {
                Servlet s = (Servlet) _servlets.pop();
                s.destroy();
            }
            _config = null;
        } finally {
            super.stop();
            // pop run-as role
            if (_runAs != null && _realm != null && user != null)
                _realm.popRole(user);
        }
    }

    /* ------------------------------------------------------------ */
    /** Get the servlet.
     * @return The servlet
     */
    public synchronized Servlet getServlet() throws ServletException {
        // Handle previous unavailability
        if (_unavailable != 0) {
            if (_unavailable < 0 || _unavailable > 0 && System.currentTimeMillis() < _unavailable)
                throw _unavailableEx;
            _unavailable = 0;
            _unavailableEx = null;
        }

        try {
            if (_servlets != null) {
                Servlet servlet = null;
                if (_servlets.size() == 0) {
                    servlet = (Servlet) newInstance();
                    if (_config == null)
                        _config = new Config();
                    initServlet(servlet, _config);
                } else
                    servlet = (Servlet) _servlets.pop();

                return servlet;
            }

            if (_servlet == null) {
                _servlet = (Servlet) newInstance();
                if (_config == null)
                    _config = new Config();
                initServlet(_servlet, _config);
            }

            return _servlet;
        } catch (UnavailableException e) {
            _servlet = null;
            _config = null;
            return makeUnavailable(e);
        } catch (ServletException e) {
            _servlet = null;
            _config = null;
            throw e;
        } catch (Throwable e) {
            _servlet = null;
            _config = null;
            throw new ServletException("init", e);
        }
    }

    /* ------------------------------------------------------------ */
    private Servlet makeUnavailable(UnavailableException e) throws UnavailableException {
        _unavailableEx = e;
        _unavailable = -1;
        if (e.isPermanent())
            _unavailable = -1;
        else {
            if (_unavailableEx.getUnavailableSeconds() > 0)
                _unavailable = System.currentTimeMillis() + 1000 * _unavailableEx.getUnavailableSeconds();
            else
                _unavailable = System.currentTimeMillis() + 5000; // TODO configure
        }

        throw _unavailableEx;
    }

    /* ------------------------------------------------------------ */
    private void initServlet(Servlet servlet, ServletConfig config) throws ServletException {
        Principal user = null;
        try {
            // Handle run as
            if (_runAs != null && _realm != null)
                user = _realm.pushRole(null, _runAs);
            servlet.init(config);
        } finally {
            // pop run-as role
            if (_runAs != null && _realm != null && user != null)
                _realm.popRole(user);
        }
    }

    /* ------------------------------------------------------------ */
    /** Service a request with this servlet.
     */
    public void handle(ServletRequest request, ServletResponse response)
            throws ServletException, UnavailableException, IOException {
        if (_class == null)
            throw new UnavailableException("Servlet Not Initialized");

        Servlet servlet = (!_initOnStartup || _servlets != null) ? getServlet() : _servlet;
        if (servlet == null)
            throw new UnavailableException("Could not instantiate " + _class);

        // Service the request
        boolean servlet_error = true;
        Principal user = null;
        HttpRequest http_request = null;
        try {
            // Handle aliased path
            if (_forcedPath != null)
                // TODO complain about poor naming to the Jasper folks
                request.setAttribute("org.apache.catalina.jsp_file", _forcedPath);

            // Handle run as
            if (_runAs != null && _realm != null) {
                http_request = getHttpContext().getHttpConnection().getRequest();
                user = _realm.pushRole(http_request.getUserPrincipal(), _runAs);
                http_request.setUserPrincipal(user);
            }

            servlet.service(request, response);
            servlet_error = false;
        } catch (UnavailableException e) {
            if (_servlets != null && servlet != null)
                stop();
            makeUnavailable(e);
        } finally {
            // pop run-as role
            if (_runAs != null && _realm != null && user != null) {
                user = _realm.popRole(user);
                http_request.setUserPrincipal(user);
            }

            // Handle error params.
            if (servlet_error)
                request.setAttribute("javax.servlet.error.servlet_name", getName());

            // Return to singleThreaded pool
            synchronized (this) {
                if (_servlets != null && servlet != null)
                    _servlets.push(servlet);
            }
        }
    }

    /* ------------------------------------------------------------ */
    /* ------------------------------------------------------------ */
    /* ------------------------------------------------------------ */
    class Config implements ServletConfig {
        /* -------------------------------------------------------- */
        public String getServletName() {
            return getName();
        }

        /* -------------------------------------------------------- */
        public ServletContext getServletContext() {
            return ((ServletHandler) _httpHandler).getServletContext();
        }

        /* -------------------------------------------------------- */
        public String getInitParameter(String param) {
            return ServletHolder.this.getInitParameter(param);
        }

        /* -------------------------------------------------------- */
        public Enumeration getInitParameterNames() {
            return ServletHolder.this.getInitParameterNames();
        }
    }
}