com.liferay.httpservice.internal.servlet.BundleServletContext.java Source code

Java tutorial

Introduction

Here is the source code for com.liferay.httpservice.internal.servlet.BundleServletContext.java

Source

/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

package com.liferay.httpservice.internal.servlet;

import com.liferay.httpservice.internal.http.DefaultHttpContext;
import com.liferay.httpservice.internal.http.HttpServiceTracker;
import com.liferay.httpservice.servlet.BundleServletConfig;
import com.liferay.httpservice.servlet.ResourceServlet;
import com.liferay.portal.apache.bridges.struts.LiferayServletContext;
import com.liferay.portal.kernel.deploy.hot.DependencyManagementThreadLocal;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.servlet.PluginContextListener;
import com.liferay.portal.kernel.servlet.PortletSessionListenerManager;
import com.liferay.portal.kernel.util.FileUtil;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.HttpUtil;
import com.liferay.portal.kernel.util.JavaConstants;
import com.liferay.portal.kernel.util.PropertiesUtil;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.xml.Document;
import com.liferay.portal.kernel.xml.DocumentException;
import com.liferay.portal.kernel.xml.Element;
import com.liferay.portal.kernel.xml.SAXReaderUtil;
import com.liferay.portal.struts.AuthPublicPathRegistry;
import com.liferay.portal.util.Portal;
import com.liferay.portal.util.PortalUtil;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import java.net.URL;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;

import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingListener;
import javax.servlet.http.HttpSessionListener;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.wiring.BundleWiring;
import org.osgi.service.http.HttpContext;
import org.osgi.service.http.NamespaceException;

/**
 * @author Raymond Aug
 * @author Miguel Pastor
 */
public class BundleServletContext extends LiferayServletContext implements BundleReference {

    public static String getServletContextName(Bundle bundle) {
        return getServletContextName(bundle, false);
    }

    public static String getServletContextName(Bundle bundle, boolean generate) {

        Dictionary<String, String> headers = bundle.getHeaders();

        String webContextPath = headers.get("Web-ContextPath");

        if (Validator.isNotNull(webContextPath)) {
            return webContextPath.substring(1);
        }

        String deploymentContext = null;

        try {
            String pluginPackageXml = HttpUtil
                    .URLtoString(bundle.getResource("/WEB-INF/liferay-plugin-package.xml"));

            if (pluginPackageXml != null) {
                Document document = SAXReaderUtil.read(pluginPackageXml);

                Element rootElement = document.getRootElement();

                deploymentContext = GetterUtil.getString(rootElement.elementText("recommended-deployment-context"));
            } else {
                String pluginPackageProperties = HttpUtil
                        .URLtoString(bundle.getResource("/WEB-INF/liferay-plugin-package.properties"));

                if (pluginPackageProperties != null) {
                    if (_log.isDebugEnabled()) {
                        _log.debug("Reading plugin package from " + "liferay-plugin-package.properties");
                    }

                    Properties properties = PropertiesUtil.load(pluginPackageProperties);

                    deploymentContext = GetterUtil
                            .getString(properties.getProperty("recommended-deployment-context"), deploymentContext);
                }
            }
        } catch (Exception e) {
            if (_log.isWarnEnabled()) {
                _log.warn(e, e);
            }
        }

        if (Validator.isNull(deploymentContext) && generate) {
            deploymentContext = PortalUtil.getJsSafePortletId(bundle.getSymbolicName());
        }

        if (Validator.isNotNull(deploymentContext) && deploymentContext.startsWith(StringPool.SLASH)) {

            deploymentContext = deploymentContext.substring(1);
        }

        return deploymentContext;
    }

    public BundleServletContext(Bundle bundle, String servletContextName, ServletContext servletContext) {

        super(servletContext);

        _bundle = bundle;
        _servletContextName = servletContextName;

        _httpContext = new DefaultHttpContext(_bundle);
    }

    public void close() {
        _httpServiceTracker.close();

        _serviceRegistration.unregister();

        FileUtil.deltree(_tempDir);
    }

    @Override
    public Object getAttribute(String name) {
        if (name.equals(JavaConstants.JAVAX_SERVLET_CONTEXT_TEMPDIR)) {
            return getTempDir();
        } else if (name.equals("osgi-bundle")) {
            return _bundle;
        } else if (name.equals("osgi-bundlecontext")) {
            return _bundle.getBundleContext();
        }

        Object value = _contextAttributes.get(name);

        if (value == null) {
            if (name.equals(PluginContextListener.PLUGIN_CLASS_LOADER)) {
                return getClassLoader();
            } else if (name.equals("org.apache.catalina.JSP_PROPERTY_GROUPS")) {
                value = new HashMap<Object, Object>();

                _contextAttributes.put(name, value);
            } else if (name.equals("org.apache.tomcat.InstanceManager")) {
                return super.getAttribute(name);
            }
        }

        return value;
    }

    @Override
    public Bundle getBundle() {
        return _bundle;
    }

    @Override
    public ClassLoader getClassLoader() {
        ClassLoader classLoader = (ClassLoader) _contextAttributes.get(PluginContextListener.PLUGIN_CLASS_LOADER);

        if (classLoader == null) {
            BundleWiring bundleWiring = _bundle.adapt(BundleWiring.class);

            classLoader = bundleWiring.getClassLoader();

            _contextAttributes.put(PluginContextListener.PLUGIN_CLASS_LOADER, classLoader);
        }

        return classLoader;
    }

    @Override
    public String getContextPath() {
        if (_contextPath != null) {
            return _contextPath;
        }

        StringBundler sb = new StringBundler(5);

        String contextPath = super.getContextPath();

        if (!contextPath.equals(StringPool.SLASH)) {
            sb.append(contextPath);
        }

        sb.append(PortalUtil.getPathContext());
        sb.append(Portal.PATH_MODULE);
        sb.append(StringPool.SLASH);
        sb.append(getServletContextName());

        _contextPath = sb.toString();

        return _contextPath;
    }

    public HttpContext getHttpContext() {
        return _httpContext;
    }

    @Override
    public String getInitParameter(String name) {
        return _initParameters.get(name);
    }

    @Override
    public Enumeration<String> getInitParameterNames() {
        return Collections.enumeration(_initParameters.keySet());
    }

    @Override
    public String getRealPath(String path) {
        URL url = _httpContext.getResource(path);

        if (url != null) {
            return url.toExternalForm();
        }

        return path;
    }

    @Override
    public RequestDispatcher getRequestDispatcher(String path) {
        String portalContextPath = PortalUtil.getPathContext();

        String contextPath = getContextPath();

        if (Validator.isNotNull(portalContextPath) && contextPath.startsWith(portalContextPath)) {

            contextPath = contextPath.substring(portalContextPath.length());
        }

        if (path.startsWith(_PATH_MODULE_SLASH) && path.startsWith(contextPath)) {

            path = path.substring(contextPath.length());
        }

        if (Validator.isNull(path)) {
            path = StringPool.SLASH;
        }

        if (!isValidPath(path)) {
            return null;
        }

        BundleFilterChain bundleFilterChain = getFilterChain(path);

        if (_servletsByURLPatterns.containsKey(path)) {
            bundleFilterChain.setServlet(_servletsByURLPatterns.get(path));

            return new BundleRequestDispatcher(path, false, path, this, bundleFilterChain);
        }

        String extension = StringUtil.toLowerCase(FileUtil.getExtension(path));

        boolean extensionMapping = false;

        if (Validator.isNotNull(extension)) {
            extension = "*.".concat(extension);

            extensionMapping = true;
        }

        String alias = path.substring(0, path.lastIndexOf(StringPool.SLASH));

        while (alias.length() != 0) {
            if (_servletsByURLPatterns.containsKey(alias)) {
                bundleFilterChain.setServlet(_servletsByURLPatterns.get(alias));

                return new BundleRequestDispatcher(alias, false, path, this, bundleFilterChain);
            } else if (_servletsByURLPatterns.containsKey(alias.concat(extension))) {

                bundleFilterChain.setServlet(_servletsByURLPatterns.get(alias.concat(extension)));

                return new BundleRequestDispatcher(alias.concat(extension), true, path, this, bundleFilterChain);
            }

            alias = path.substring(0, alias.lastIndexOf(StringPool.SLASH));
        }

        if (_servletsByURLPatterns.containsKey(StringPool.SLASH.concat(extension))) {

            bundleFilterChain.setServlet(_servletsByURLPatterns.get(StringPool.SLASH.concat(extension)));

            return new BundleRequestDispatcher(StringPool.SLASH.concat(extension), extensionMapping, path, this,
                    bundleFilterChain);
        }

        if (_servletsByURLPatterns.containsKey(StringPool.SLASH)) {
            bundleFilterChain.setServlet(_servletsByURLPatterns.get(StringPool.SLASH));

            return new BundleRequestDispatcher(StringPool.SLASH, false, path, this, bundleFilterChain);
        }

        return null;
    }

    @Override
    public URL getResource(String path) {
        return _httpContext.getResource(path);
    }

    @Override
    public InputStream getResourceAsStream(String path) {
        try {
            URL url = getResource(path);

            if (url != null) {
                return url.openStream();
            }
        } catch (IOException ioe) {
            _log.error(ioe, ioe);
        }

        return null;
    }

    @Override
    public Set<String> getResourcePaths(String path) {
        Set<String> paths = new HashSet<String>();

        Enumeration<String> enumeration = _bundle.getEntryPaths(path);

        if (enumeration == null) {
            return Collections.emptySet();
        }

        while (enumeration.hasMoreElements()) {
            String entryPath = enumeration.nextElement();

            paths.add(StringPool.SLASH.concat(entryPath));
        }

        return paths;
    }

    @Override
    public Servlet getServlet(String name) {
        return _servletsByServletNames.get(name);
    }

    @Override
    public String getServletContextName() {
        return _servletContextName;
    }

    public List<ServletRequestAttributeListener> getServletRequestAttributeListeners() {

        return _servletRequestAttributeListeners;
    }

    public List<ServletRequestListener> getServletRequestListeners() {
        return _servletRequestListeners;
    }

    public void open() throws DocumentException {
        Hashtable<String, Object> properties = new Hashtable<String, Object>();

        properties.put("bundle", _bundle);
        properties.put("bundle.id", _bundle.getBundleId());
        properties.put("bundle.symbolicName", _bundle.getSymbolicName());
        properties.put("bundle.version", _bundle.getVersion());
        properties.put("Web-ContextPath", StringPool.SLASH.concat(_servletContextName));

        BundleContext bundleContext = _bundle.getBundleContext();

        _serviceRegistration = bundleContext.registerService(BundleServletContext.class, this, properties);

        _httpServiceTracker = new HttpServiceTracker(bundleContext, _bundle);

        _httpServiceTracker.open();
    }

    public void registerFilter(String filterName, List<String> urlPatterns, Filter filter,
            Map<String, String> initParameters, HttpContext httpContext)
            throws NamespaceException, ServletException {

        validateFilter(filterName, filter, urlPatterns, httpContext);

        Thread currentThread = Thread.currentThread();

        ClassLoader contextClassLoader = currentThread.getContextClassLoader();

        try {
            currentThread.setContextClassLoader(getClassLoader());

            FilterConfig filterConfig = new BundleFilterConfig(this, filterName, initParameters, httpContext);

            filter.init(filterConfig);

            _filtersByFilterNames.put(filterName, filter);

            if (_log.isInfoEnabled()) {
                _log.info("Registered filter " + filterName);
            }

            for (String urlPattern : urlPatterns) {
                _filtersByURLPatterns.put(urlPattern, filter);

                if (_log.isInfoEnabled()) {
                    _log.info("Mapped filter " + filterName + " to " + getContextPath() + urlPattern);
                }
            }

            FilterServiceRanking filterServiceRanking = new FilterServiceRanking();

            filterServiceRanking.setFilterName(filterName);

            int serviceRanking = _FILTER_SERVICE_RANKING_DEFAULT;

            if (initParameters != null) {
                serviceRanking = GetterUtil.getInteger(initParameters.remove("service.ranking"),
                        _FILTER_SERVICE_RANKING_DEFAULT);
            }

            filterServiceRanking.setServiceRanking(serviceRanking);
            filterServiceRanking.setUrlPattterns(urlPatterns);

            // Filters are sorted based on their service ranking value where the
            // default service ranking is 10 for those filters that do not
            // specify a specific service ranking.

            // Filters are first sorted based on the service ranking where
            // filters with a smaller service ranking appear earlier in the
            // list, and then based on when the filter was registered where
            // those that are registered earlier appear earlier in the list.

            _filterServiceRankings.add(filterServiceRanking);
        } finally {
            currentThread.setContextClassLoader(contextClassLoader);
        }
    }

    public void registerFilter(String filterName, String urlPattern, Filter filter,
            Map<String, String> initParameters, HttpContext httpContext)
            throws NamespaceException, ServletException {

        List<String> urlPatterns = Arrays.asList(urlPattern);

        registerFilter(filterName, urlPatterns, filter, initParameters, httpContext);
    }

    public void registerListener(Object listener, Map<String, String> initParameters, HttpContext httpContext) {

        Thread currentThread = Thread.currentThread();

        ClassLoader contextClassLoader = currentThread.getContextClassLoader();

        boolean enabled = DependencyManagementThreadLocal.isEnabled();

        try {
            currentThread.setContextClassLoader(getClassLoader());

            DependencyManagementThreadLocal.setEnabled(false);

            if (initParameters != null) {
                Set<Entry<String, String>> set = initParameters.entrySet();

                Iterator<Entry<String, String>> iterator = set.iterator();

                while (iterator.hasNext()) {
                    Entry<String, String> entry = iterator.next();

                    String value = entry.getValue();

                    if (_initParameters.containsKey(value)) {
                        continue;
                    }

                    _initParameters.put(entry.getKey(), value);
                }
            }

            if (listener instanceof HttpSessionActivationListener) {
                PortletSessionListenerManager
                        .addHttpSessionActivationListener((HttpSessionActivationListener) listener);
            }

            if (listener instanceof HttpSessionAttributeListener) {
                PortletSessionListenerManager
                        .addHttpSessionAttributeListener((HttpSessionAttributeListener) listener);
            }

            if (listener instanceof HttpSessionBindingListener) {
                PortletSessionListenerManager.addHttpSessionBindingListener((HttpSessionBindingListener) listener);
            }

            if (listener instanceof HttpSessionListener) {
                PortletSessionListenerManager.addHttpSessionListener((HttpSessionListener) listener);
            }

            if (listener instanceof ServletContextAttributeListener) {
                _servletContextAttributeListeners.add((ServletContextAttributeListener) listener);
            }

            if (listener instanceof ServletContextListener) {
                ServletContextListener servletContextListener = (ServletContextListener) listener;

                ServletContextEvent servletContextEvent = new ServletContextEvent(this);

                servletContextListener.contextInitialized(servletContextEvent);

                _servletContextListeners.add(servletContextListener);
            }

            if (listener instanceof ServletRequestAttributeListener) {
                _servletRequestAttributeListeners.add((ServletRequestAttributeListener) listener);
            }

            if (listener instanceof ServletRequestListener) {
                _servletRequestListeners.add((ServletRequestListener) listener);
            }
        } finally {
            DependencyManagementThreadLocal.setEnabled(enabled);

            currentThread.setContextClassLoader(contextClassLoader);
        }
    }

    public void registerResources(String alias, String name, HttpContext httpContext) throws NamespaceException {

        Map<String, String> initParameters = new Hashtable<String, String>();

        initParameters.put("alias", alias);

        if (name == null) {
            throw new IllegalArgumentException("Name is null");
        }

        if (name.endsWith(StringPool.SLASH) && !name.equals(StringPool.SLASH)) {
            throw new IllegalArgumentException("Invalid name " + name);
        }

        initParameters.put("name", name);

        Servlet resourceServlet = new ResourceServlet();

        try {
            registerServlet(name, alias, resourceServlet, initParameters, httpContext);

            AuthPublicPathRegistry.register(Portal.PATH_MODULE + StringPool.SLASH + _servletContextName + alias);
        } catch (ServletException se) {
            throw new IllegalArgumentException(se);
        }
    }

    public void registerServlet(String servletName, List<String> urlPatterns, Servlet servlet,
            Map<String, String> initParameters, HttpContext httpContext)
            throws NamespaceException, ServletException {

        validateServlet(servletName, servlet, urlPatterns, httpContext);

        Thread currentThread = Thread.currentThread();

        ClassLoader contextClassLoader = currentThread.getContextClassLoader();

        try {
            currentThread.setContextClassLoader(getClassLoader());

            ServletConfig servletConfig = new BundleServletConfig(this, servletName, initParameters, httpContext);

            servlet.init(servletConfig);

            _servletsByServletNames.put(servletName, servlet);

            if (_log.isInfoEnabled()) {
                _log.info("Registered servlet " + servletName);
            }

            for (String urlPattern : urlPatterns) {
                _servletsByURLPatterns.put(urlPattern, servlet);

                if (_log.isInfoEnabled()) {
                    _log.info("Mapped servlet " + servletName + " to " + getContextPath() + urlPattern);
                }
            }
        } finally {
            currentThread.setContextClassLoader(contextClassLoader);
        }
    }

    public void registerServlet(String servletName, String urlPattern, Servlet servlet,
            Map<String, String> initParameters, HttpContext httpContext)
            throws NamespaceException, ServletException {

        List<String> urlPatterns = Arrays.asList(urlPattern);

        registerServlet(servletName, urlPatterns, servlet, initParameters, httpContext);
    }

    @Override
    public void removeAttribute(String name) {
        Object value = _contextAttributes.remove(name);

        for (ServletContextAttributeListener servletContextAttributeListener : _servletContextAttributeListeners) {

            servletContextAttributeListener.attributeRemoved(new ServletContextAttributeEvent(this, name, value));
        }
    }

    @Override
    public void setAttribute(String name, Object value) {
        if (name.equals(JavaConstants.JAVAX_SERVLET_CONTEXT_TEMPDIR)
                || name.equals(PluginContextListener.PLUGIN_CLASS_LOADER)) {

            return;
        }

        Object originalValue = _contextAttributes.get(name);

        _contextAttributes.put(name, value);

        for (ServletContextAttributeListener servletContextAttributeListener : _servletContextAttributeListeners) {

            ServletContextAttributeEvent servletContextAttributeEvent = new ServletContextAttributeEvent(this, name,
                    value);

            if (originalValue != null) {
                servletContextAttributeListener.attributeReplaced(servletContextAttributeEvent);
            } else {
                servletContextAttributeListener.attributeAdded(servletContextAttributeEvent);
            }
        }
    }

    public void setServletContextName(String servletContextName) {
        _servletContextName = servletContextName;
    }

    public void unregisterFilter(String filterName) {
        Filter filter = _filtersByFilterNames.remove(filterName);

        if (filter == null) {
            return;
        }

        filter.destroy();

        unregisterFilterByServiceRanking(filterName);
        unregisterFilterByURLMapping(filterName, filter);
    }

    public void unregisterListener(Object listener) {
        Thread currentThread = Thread.currentThread();

        ClassLoader contextClassLoader = currentThread.getContextClassLoader();

        boolean enabled = DependencyManagementThreadLocal.isEnabled();

        try {
            currentThread.setContextClassLoader(getClassLoader());

            DependencyManagementThreadLocal.setEnabled(false);

            if (listener instanceof HttpSessionActivationListener) {
                PortletSessionListenerManager
                        .removeHttpSessionActivationListener((HttpSessionActivationListener) listener);
            }

            if (listener instanceof HttpSessionAttributeListener) {
                PortletSessionListenerManager
                        .removeHttpSessionAttributeListener((HttpSessionAttributeListener) listener);
            }

            if (listener instanceof HttpSessionBindingListener) {
                PortletSessionListenerManager
                        .removeHttpSessionBindingListener((HttpSessionBindingListener) listener);
            }

            if (listener instanceof HttpSessionListener) {
                PortletSessionListenerManager.removeHttpSessionListener((HttpSessionListener) listener);
            }

            if (listener instanceof ServletContextAttributeListener) {
                _servletContextAttributeListeners.remove(listener);
            }

            if (listener instanceof ServletContextListener) {
                if (_servletContextListeners.contains(listener)) {
                    _servletContextListeners.remove(listener);

                    ServletContextListener servletContextListener = (ServletContextListener) listener;

                    ServletContextEvent servletContextEvent = new ServletContextEvent(this);

                    servletContextListener.contextDestroyed(servletContextEvent);
                }
            }

            if (listener instanceof ServletRequestAttributeListener) {
                _servletRequestAttributeListeners.remove(listener);
            }

            if (listener instanceof ServletRequestListener) {
                _servletRequestListeners.remove(listener);
            }
        } finally {
            DependencyManagementThreadLocal.setEnabled(enabled);

            currentThread.setContextClassLoader(contextClassLoader);
        }
    }

    public void unregisterServlet(String servletName) {
        Servlet servlet = _servletsByServletNames.remove(servletName);

        if (servlet == null) {
            return;
        }

        servlet.destroy();

        Set<Map.Entry<String, Servlet>> set = _servletsByURLPatterns.entrySet();

        Iterator<Map.Entry<String, Servlet>> iterator = set.iterator();

        while (iterator.hasNext()) {
            Map.Entry<String, Servlet> entry = iterator.next();

            Servlet curServlet = entry.getValue();

            if (curServlet != servlet) {
                continue;
            }

            AuthPublicPathRegistry
                    .unregister(Portal.PATH_MODULE + StringPool.SLASH + _servletContextName + entry.getKey());

            iterator.remove();

            if (_log.isInfoEnabled()) {
                String urlPattern = entry.getKey();

                _log.info("Unmapped servlet " + servletName + " from " + urlPattern);
            }
        }

        if (_log.isInfoEnabled()) {
            _log.info("Unregistered servlet " + servletName);
        }
    }

    protected BundleFilterChain getFilterChain(String path) {
        BundleFilterChain bundleFilterChain = new BundleFilterChain();

        for (FilterServiceRanking filterServiceRanking : _filterServiceRankings) {

            String filterName = filterServiceRanking.getFilterName();

            Filter filter = _filtersByFilterNames.get(filterName);

            List<String> urlPatterns = filterServiceRanking.getUrlPatterns();

            for (String urlPattern : urlPatterns) {
                if (urlPattern.equals(path)) {
                    bundleFilterChain.addFilter(filter);

                    break;
                }

                if (urlPattern.contains(StringPool.STAR)) {
                    urlPattern = urlPattern.replaceAll("\\".concat(StringPool.STAR), ".*");
                }

                if (path.matches(urlPattern)) {
                    bundleFilterChain.addFilter(filter);
                }
            }
        }

        return bundleFilterChain;
    }

    protected File getTempDir() {
        if (_tempDir != null) {
            return _tempDir;
        }

        File parentTempDir = (File) super.getAttribute(JavaConstants.JAVAX_SERVLET_CONTEXT_TEMPDIR);

        File tempDir = new File(parentTempDir, _servletContextName);

        if (!tempDir.exists() && !tempDir.mkdirs()) {
            throw new IllegalStateException("Unable to make temporary directory " + tempDir);
        }

        _tempDir = tempDir;

        return _tempDir;
    }

    protected boolean isValidPath(String path) {
        if (!path.startsWith(StringPool.SLASH)) {
            path = StringPool.SLASH.concat(path);
        }

        for (String illegalPath : _ILLEGAL_PATHS) {
            if (path.startsWith(illegalPath)) {
                return false;
            }
        }

        return true;
    }

    protected void unregisterFilterByServiceRanking(String filterName) {
        Iterator<FilterServiceRanking> iterator = _filterServiceRankings.iterator();

        while (iterator.hasNext()) {
            FilterServiceRanking filterServiceRanking = iterator.next();

            if (!filterName.equals(filterServiceRanking.getFilterName())) {
                continue;
            }

            iterator.remove();
        }
    }

    protected void unregisterFilterByURLMapping(String filterName, Filter filter) {

        Set<Map.Entry<String, Filter>> set = _filtersByURLPatterns.entrySet();

        Iterator<Map.Entry<String, Filter>> iterator = set.iterator();

        while (iterator.hasNext()) {
            Map.Entry<String, Filter> entry = iterator.next();

            Filter curFilter = entry.getValue();

            if (curFilter != filter) {
                continue;
            }

            iterator.remove();

            if (_log.isInfoEnabled()) {
                String urlPattern = entry.getKey();

                _log.info("Unmapped filter " + filterName + " from " + urlPattern);
            }
        }

        if (_log.isInfoEnabled()) {
            _log.info("Unregistered filter " + filterName);
        }
    }

    protected void validateFilter(String filterName, Filter filter, List<String> urlPatterns,
            HttpContext httpContext) throws NamespaceException {

        if (filter == null) {
            throw new IllegalArgumentException("Filter must not be null");
        }

        Filter registeredFilter = _filtersByFilterNames.get(filterName);

        if ((registeredFilter != null) && (registeredFilter != filter)) {
            throw new NamespaceException("A filter is already registered with the name " + filterName);
        }

        for (String urlPattern : urlPatterns) {
            validateURLPattern(urlPattern);
        }
    }

    protected void validateServlet(String servletName, Servlet servlet, List<String> urlPatterns,
            HttpContext httpContext) throws NamespaceException {

        if (servlet == null) {
            throw new IllegalArgumentException("Servlet must not be null");
        }

        Servlet registeredServlet = _servletsByServletNames.get(servletName);

        if ((registeredServlet != null) && (registeredServlet != servlet)) {
            throw new NamespaceException("A servlet is already registered with the name " + servletName);
        }

        for (String urlPattern : urlPatterns) {
            validateURLPattern(urlPattern);

            if (_servletsByURLPatterns.containsKey(urlPattern)) {
                throw new NamespaceException("A servlet is already registered with the URL pattern " + urlPattern);
            }
        }
    }

    protected void validateURLPattern(String urlPattern) {
        if (Validator.isNull(urlPattern)) {
            throw new IllegalArgumentException("An empty URL pattern is not allowed");
        }

        if (!urlPattern.startsWith(StringPool.SLASH)
                || (urlPattern.endsWith(StringPool.SLASH) && !urlPattern.equals(StringPool.SLASH))) {

            throw new IllegalArgumentException("URL patterns must start with / but cannot end with it");
        }
    }

    private static final int _FILTER_SERVICE_RANKING_DEFAULT = 10;

    private static final String[] _ILLEGAL_PATHS = new String[] { "/META-INF/", "/OSGI-INF/", "/OSGI-OPT/",
            "/WEB-INF/" };

    private static final String _PATH_MODULE_SLASH = Portal.PATH_MODULE + StringPool.SLASH;

    private static Log _log = LogFactoryUtil.getLog(BundleServletContext.class);

    private Bundle _bundle;
    private Map<String, Object> _contextAttributes = new ConcurrentHashMap<String, Object>();
    private String _contextPath;
    private Map<String, Filter> _filtersByFilterNames = new ConcurrentHashMap<String, Filter>();
    private Map<String, Filter> _filtersByURLPatterns = new ConcurrentHashMap<String, Filter>();
    private Set<FilterServiceRanking> _filterServiceRankings = new ConcurrentSkipListSet<FilterServiceRanking>(
            new FilterServiceRankingComparator());
    private HttpContext _httpContext;
    private HttpServiceTracker _httpServiceTracker;
    private Map<String, String> _initParameters = new HashMap<String, String>();
    private ServiceRegistration<BundleServletContext> _serviceRegistration;
    private List<ServletContextAttributeListener> _servletContextAttributeListeners = new ArrayList<ServletContextAttributeListener>();
    private List<ServletContextListener> _servletContextListeners = new ArrayList<ServletContextListener>();
    private String _servletContextName;
    private List<ServletRequestAttributeListener> _servletRequestAttributeListeners = new ArrayList<ServletRequestAttributeListener>();
    private List<ServletRequestListener> _servletRequestListeners = new ArrayList<ServletRequestListener>();
    private Map<String, Servlet> _servletsByServletNames = new ConcurrentHashMap<String, Servlet>();
    private Map<String, Servlet> _servletsByURLPatterns = new ConcurrentHashMap<String, Servlet>();
    private File _tempDir;

    private class FilterServiceRanking {

        @Override
        public boolean equals(Object object) {
            FilterServiceRanking filterServiceRanking = (FilterServiceRanking) object;

            if (Validator.equals(_filterName, filterServiceRanking._filterName)
                    && Validator.equals(_serviceRanking, filterServiceRanking._serviceRanking)) {

                return true;
            }

            return false;
        }

        public String getFilterName() {
            return _filterName;
        }

        public int getServiceRanking() {
            return _serviceRanking;
        }

        public long getTimestamp() {
            return _timestamp;
        }

        public List<String> getUrlPatterns() {
            return _urlPatterns;
        }

        public void setFilterName(String filterName) {
            _filterName = filterName;
        }

        public void setServiceRanking(int serviceRanking) {
            _serviceRanking = serviceRanking;
        }

        public void setUrlPattterns(List<String> urlMappings) {
            _urlPatterns = urlMappings;
        }

        private String _filterName;
        private int _serviceRanking;
        private long _timestamp = System.currentTimeMillis();
        private List<String> _urlPatterns;

    }

    private class FilterServiceRankingComparator implements Comparator<FilterServiceRanking> {

        @Override
        public int compare(FilterServiceRanking filterServiceRanking1, FilterServiceRanking filterServiceRanking2) {

            if (filterServiceRanking1.getServiceRanking() < filterServiceRanking2.getServiceRanking()) {

                return -1;
            } else if (filterServiceRanking1.getServiceRanking() > filterServiceRanking2.getServiceRanking()) {

                return 1;
            }

            if (filterServiceRanking1.getTimestamp() < filterServiceRanking2.getTimestamp()) {

                return -1;
            } else if (filterServiceRanking1.getTimestamp() > filterServiceRanking2.getTimestamp()) {

                return 1;
            }

            return 0;
        }
    }

}