org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.java Source code

Java tutorial

Introduction

Here is the source code for org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.java

Source

/*  Copyright 2007 Alin Dreghiciu.
 *
 * 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 org.ops4j.pax.web.service.jetty.internal;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.EventListener;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingListener;
import javax.servlet.http.HttpSessionListener;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jetty.server.HandlerContainer;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil;
import org.ops4j.pax.swissbox.core.ContextClassLoaderUtils;
import org.ops4j.pax.web.service.WebContainerContext;
import org.osgi.service.http.HttpContext;

class HttpServiceContext extends ServletContextHandler {

    private static final Log LOG = LogFactory.getLog(HttpServiceContext.class);

    /**
     * Context attributes.
     */
    private final Map<String, Object> m_attributes;
    private final HttpContext m_httpContext;
    /**
     * Access controller context of the bundle that registred the http context.
     */
    private final AccessControlContext m_accessControllerContext;

    HttpServiceContext(final HandlerContainer parent, final Map<String, String> initParams,
            final Map<String, Object> attributes, final String contextName, final HttpContext httpContext,
            final AccessControlContext accessControllerContext) {
        super(parent, "/" + contextName, SESSIONS | SECURITY);
        getInitParams().putAll(initParams);
        m_attributes = attributes;
        m_httpContext = httpContext;
        m_accessControllerContext = accessControllerContext;

        _scontext = new SContext();
        setServletHandler(new HttpServiceServletHandler(httpContext));
        setErrorHandler(new ErrorPageErrorHandler());
    }

    @Override
    protected void doStart() throws Exception {
        super.doStart();
        if (m_attributes != null) {
            for (Map.Entry<String, ?> attribute : m_attributes.entrySet()) {
                _scontext.setAttribute(attribute.getKey(), attribute.getValue());
            }
        }
        LOG.debug("Started servlet context for http context [" + m_httpContext + "]");
    }

    @Override
    protected void doStop() throws Exception {
        super.doStop();
        LOG.debug("Stopped servlet context for http context [" + m_httpContext + "]");
    }

    @Override
    public void doHandle(String target, Request baseRequest, HttpServletRequest request,
            HttpServletResponse response) throws IOException, ServletException {
        LOG.debug("Handling request for [" + target + "] using http context [" + m_httpContext + "]");
        super.doHandle(target, baseRequest, request, response);
    }

    @Override
    public void setEventListeners(final EventListener[] eventListeners) {
        if (_sessionHandler != null) {
            _sessionHandler.clearEventListeners();
        }

        super.setEventListeners(eventListeners);
        if (_sessionHandler != null) {
            for (int i = 0; eventListeners != null && i < eventListeners.length; i++) {
                EventListener listener = eventListeners[i];

                if ((listener instanceof HttpSessionActivationListener)
                        || (listener instanceof HttpSessionAttributeListener)
                        || (listener instanceof HttpSessionBindingListener)
                        || (listener instanceof HttpSessionListener)) {
                    _sessionHandler.addEventListener(listener);
                }

            }
        }
    }

    /**
     * If the listener is a servlet conetx listener and the context is already started, notify the servlet context
     * listener about the fact that context is started. This has to be done separately as the listener could be added
     * after the context is already started, case when servlet context listeners are not notified anymore.
     *
     * @param listener to be notified.
     */
    @Override
    public void addEventListener(final EventListener listener) {
        super.addEventListener(listener);
        if (isStarted() && listener instanceof ServletContextListener) {
            try {
                ContextClassLoaderUtils.doWithClassLoader(getClassLoader(), new Callable<Void>() {

                    public Void call() {
                        ((ServletContextListener) listener).contextInitialized(new ServletContextEvent(_scontext));
                        return null;
                    }

                });
            } catch (Exception e) {
                if (e instanceof RuntimeException) {
                    throw (RuntimeException) e;
                }
                LOG.error("Ignored exception during listener registration", e);
            }
        }
    }

    @Override
    protected boolean isProtectedTarget(String target) { //Fixes PAXWEB-196  and PAXWEB-211
        while (target.startsWith("//"))
            target = URIUtil.compactPath(target);

        return StringUtil.startsWithIgnoreCase(target, "/web-inf")
                || StringUtil.startsWithIgnoreCase(target, "/meta-inf")
                || StringUtil.startsWithIgnoreCase(target, "/osgi-inf")
                || StringUtil.startsWithIgnoreCase(target, "/osgi-opt");
    }

    @Override
    public String toString() {
        return new StringBuilder().append(this.getClass().getSimpleName()).append("{").append("httpContext=")
                .append(m_httpContext).append("}").toString();
    }

    public class SContext extends Context {

        @Override
        public String getRealPath(final String path) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("getting real path: [" + path + "]");
            }

            URL resource = getResource(path);
            if (resource != null) {
                String protocol = resource.getProtocol();
                if (protocol.equals("file")) {
                    String fileName = resource.getFile();
                    if (fileName != null) {
                        File file = new File(fileName);
                        if (file.exists()) {
                            String realPath = file.getAbsolutePath();
                            if (LOG.isDebugEnabled()) {
                                LOG.debug("found real path: [" + realPath + "]");
                            }
                            return realPath;
                        }
                    }
                }
            }
            return null;
        }

        @Override
        public URL getResource(final String path) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("getting resource: [" + path + "]");
            }
            URL resource = null;
            try {
                resource = AccessController.doPrivileged(new PrivilegedExceptionAction<URL>() {
                    public URL run() throws Exception {
                        return m_httpContext.getResource(path);
                    }
                }, m_accessControllerContext);
                if (LOG.isDebugEnabled()) {
                    LOG.debug("found resource: " + resource);
                }
            } catch (PrivilegedActionException e) {
                LOG.warn("Unauthorized access: " + e.getMessage());
            }
            return resource;
        }

        @Override
        public InputStream getResourceAsStream(final String path) {
            final URL url = getResource(path);
            if (url != null) {
                try {
                    return AccessController.doPrivileged(new PrivilegedExceptionAction<InputStream>() {
                        public InputStream run() throws Exception {
                            try {
                                return url.openStream();
                            } catch (IOException e) {
                                LOG.warn("URL canot be accessed: " + e.getMessage());
                            }
                            return null;
                        }

                    }, m_accessControllerContext);
                } catch (PrivilegedActionException e) {
                    LOG.warn("Unauthorized access: " + e.getMessage());
                }

            }
            return null;
        }

        /**
         * Delegate to http context in case that the http context is an {@link WebContainerContext}.
         * {@inheritDoc}
         */
        @Override
        public Set getResourcePaths(final String path) {
            if (m_httpContext instanceof WebContainerContext) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("getting resource paths for : [" + path + "]");
                }
                try {
                    final Set<String> paths = AccessController
                            .doPrivileged(new PrivilegedExceptionAction<Set<String>>() {
                                public Set<String> run() throws Exception {
                                    return ((WebContainerContext) m_httpContext).getResourcePaths(path);
                                }
                            }, m_accessControllerContext);
                    if (paths == null) {
                        return null;
                    }
                    // Servlet specs mandates that the paths must start with an slash "/"
                    final Set<String> slashedPaths = new HashSet<String>();
                    for (String foundPath : paths) {
                        if (foundPath != null) {
                            if (foundPath.trim().startsWith("/")) {
                                slashedPaths.add(foundPath.trim());
                            } else {
                                slashedPaths.add("/" + foundPath.trim());
                            }
                        }
                    }
                    if (LOG.isDebugEnabled()) {
                        LOG.debug("found resource paths: " + paths);
                    }
                    return slashedPaths;
                } catch (PrivilegedActionException e) {
                    LOG.warn("Unauthorized access: " + e.getMessage());
                    return null;
                }
            } else {
                return super.getResourcePaths(path);
            }
        }

        @Override
        public String getMimeType(final String name) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("getting mime type for: [" + name + "]");
            }
            return m_httpContext.getMimeType(name);
        }

    }

}