001/*
002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     bstefanescu
011 */
012package org.nuxeo.ecm.webengine.jaxrs.servlet;
013
014import java.io.IOException;
015
016import javax.servlet.ServletConfig;
017import javax.servlet.ServletException;
018import javax.servlet.http.HttpServlet;
019import javax.servlet.http.HttpServletRequest;
020import javax.servlet.http.HttpServletResponse;
021
022import org.nuxeo.ecm.webengine.jaxrs.BundleNotFoundException;
023import org.nuxeo.ecm.webengine.jaxrs.servlet.config.ListenerSetDescriptor;
024import org.nuxeo.ecm.webengine.jaxrs.servlet.config.ServletDescriptor;
025import org.nuxeo.ecm.webengine.jaxrs.servlet.config.ServletRegistry;
026
027/**
028 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
029 */
030public class ServletHolder extends HttpServlet {
031
032    private static final long serialVersionUID = 1L;
033
034    protected RequestChain chain;
035
036    protected ServletDescriptor descriptor;
037
038    protected volatile boolean initDone = false;
039
040    protected String getName(ServletConfig config) {
041        String name = config.getInitParameter(ServletRegistry.SERVLET_NAME);
042        if (name == null) {
043            name = config.getServletName();
044        }
045        return name;
046    }
047
048    protected ServletDescriptor getDescriptor(ServletConfig config) throws ServletException {
049        String name = getName(config);
050        if (name == null) {
051            throw new ServletException("No name defined for the ServletHolder. Check your servlet contributions.");
052        }
053        ServletDescriptor desc = ServletRegistry.getInstance().getServletDescriptor(name);
054        if (desc == null) {
055            throw new ServletException("No such servlet descriptor: " + name);
056        }
057        return desc;
058    }
059
060    @Override
061    public void init(ServletConfig config) throws ServletException {
062        try {
063            descriptor = getDescriptor(config);
064            chain = new RequestChain(descriptor.getServlet(), descriptor.getFilters());
065            ListenerSetDescriptor listeners = descriptor.getListenerSet();
066            if (listeners != null) {
067                // initialize listeners if not already initialized
068                listeners.init(config);
069            }
070            super.init(config);
071            // lazy chain.init(descriptor, config);
072        } catch (ServletException e) {
073            throw e;
074        } catch (ReflectiveOperationException | BundleNotFoundException e) {
075            throw new ServletException("Initialization exception for servlet " + config.getServletName(), e);
076        }
077    }
078
079    @Override
080    public void destroy() {
081        super.destroy();
082        initDone = false;
083        if (chain != null) {
084            chain.destroy();
085            chain = null;
086        }
087    }
088
089    @Override
090    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException,
091            IOException {
092        Thread t = Thread.currentThread();
093        ClassLoader cl = t.getContextClassLoader();
094        try {
095            if (!initDone) {
096                lazyInit();
097            }
098            // use servlet class loader as the context class loader
099            t.setContextClassLoader(chain.servlet.getClass().getClassLoader());
100            chain.execute(request, response);
101        } finally {
102            t.setContextClassLoader(cl);
103        }
104    }
105
106    protected synchronized void lazyInit() throws ServletException {
107        try {
108            chain.init(descriptor, getServletConfig());
109        } finally {
110            initDone = true;
111        }
112    }
113
114}