org.apache.hadoop.fs.webdav.WebdavServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.fs.webdav.WebdavServlet.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.hadoop.fs.webdav;

import java.net.MalformedURLException;
import java.io.*;
import java.util.*;

import javax.servlet.http.*;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.security.UnixUserGroupInformation;
import org.apache.hadoop.fs.permission.AccessControlException;
import org.apache.jackrabbit.webdav.server.AbstractWebdavServlet;
import org.apache.jackrabbit.webdav.*;
import org.apache.jackrabbit.webdav.simple.LocatorFactoryImpl;
import org.apache.jackrabbit.webdav.simple.ResourceConfig;
import org.apache.jackrabbit.webdav.simple.ResourceFactoryImpl;
import org.mortbay.jetty.webapp.WebAppContext;

import java.net.URL;
import org.apache.tika.detect.Detector;
import org.apache.tika.mime.MimeTypeException;
import org.apache.tika.mime.MimeTypesFactory;

public class WebdavServlet extends AbstractWebdavServlet {

    private static final long serialVersionUID = 1L;

    /**
     * the default logger
     */
    private static final Log log = LogFactory.getLog(WebdavServlet.class);

    /**
     * init param name of the repository prefix
     */
    public static final String INIT_PARAM_RESOURCE_PATH_PREFIX = "resource-path-prefix";

    /**
     * Name of the optional init parameter that defines the value of the
     * 'WWW-Authenticate' header.<p/>
     * If the parameter is omitted the default value
     * {@link #DEFAULT_AUTHENTICATE_HEADER "Basic Realm=Hadoop Webdav Server"}
     * is used.
     *
     * @see #getAuthenticateHeaderValue()
     */
    public static final String INIT_PARAM_AUTHENTICATE_HEADER = "authenticate-header";

    /** the 'missing-auth-mapping' init parameter */
    public final static String INIT_PARAM_MISSING_AUTH_MAPPING = "missing-auth-mapping";

    /**
     * Name of the init parameter that specify a separate configuration used
     * for filtering the resources displayed.
     */
    public static final String INIT_PARAM_RESOURCE_CONFIG = "resource-config";

    /**
     * Servlet context attribute used to store the path prefix instead of
     * having a static field with this servlet. The latter causes problems
     * when running multiple
     */
    public static final String CTX_ATTR_RESOURCE_PATH_PREFIX = "hadoop.webdav.resourcepath";

    /**
     * the resource path prefix
     */
    private String resourcePathPrefix;

    /**
     * Header value as specified in the {@link #INIT_PARAM_AUTHENTICATE_HEADER} parameter.
     */
    private String authenticate_header;

    /**
     * the resource factory
     */
    private DavResourceFactory resourceFactory;

    /**
     * the locator factory
     */
    private DavLocatorFactory locatorFactory;

    /**
     * the webdav session provider
     */
    private DavSessionProvider davSessionProvider;

    /**
     * The config
     */
    private ResourceConfig config;

    private static Configuration hadoopConfig = new Configuration();

    private static String currentUserName;

    public static final String INIT_PARAM_MIME_INFO = "mime-info";

    /**
     * Init this servlet
     *
     * @throws ServletException
     */
    @Override
    public void init() throws ServletException {
        super.init();
        resourcePathPrefix = getInitParameter(INIT_PARAM_RESOURCE_PATH_PREFIX);
        if (resourcePathPrefix == null) {
            log.debug("Missing path prefix -> setting to empty string.");
            resourcePathPrefix = "";
        } else if (resourcePathPrefix.endsWith("/")) {
            log.debug("Path prefix ends with '/' -> removing trailing slash.");
            resourcePathPrefix = resourcePathPrefix.substring(0, resourcePathPrefix.length() - 1);
        }

        getServletContext().setAttribute(CTX_ATTR_RESOURCE_PATH_PREFIX, resourcePathPrefix);
        log.info(INIT_PARAM_RESOURCE_PATH_PREFIX + " = '" + resourcePathPrefix + "'");

        authenticate_header = getInitParameter(INIT_PARAM_AUTHENTICATE_HEADER);
        if (authenticate_header == null) {
            authenticate_header = DEFAULT_AUTHENTICATE_HEADER;
        }
        log.info("WWW-Authenticate header = '" + authenticate_header + "'");

        log.info("INIT_PARAMETERS: ");
        Enumeration e2 = getInitParameterNames();
        while (e2.hasMoreElements()) {
            String name = (String) e2.nextElement();
            log.info("-- " + name + ": ");
        }
        log.info("ServletInfo: " + getServletInfo());
        log.info("ServletName: " + getServletName());

        log.info("SERVLET_CONFIG_PARAMETERS: ");
        Enumeration e3 = getServletConfig().getInitParameterNames();
        while (e3.hasMoreElements()) {
            String name = (String) e3.nextElement();
            log.info("-- " + name + ": ");
        }

        log.info("SERVLET_CONTEXT_PARAMETERS: ");
        Enumeration e4 = getServletContext().getInitParameterNames();
        while (e4.hasMoreElements()) {
            String name = (String) e4.nextElement();
            log.info("-- " + name + ": ");
        }

        log.info("SERVLET_CONTEXT_ATTRIBUTES: ");
        Enumeration e5 = getServletContext().getAttributeNames();
        while (e5.hasMoreElements()) {
            String name = (String) e5.nextElement();
            log.info("-- " + name + ": ");
        }

        String configParam = getInitParameter(INIT_PARAM_RESOURCE_CONFIG);
        if (configParam != null) {
            try {
                config = new ResourceConfig(getDetector());
                config.parse(getServletContext().getResource(configParam));
            } catch (MalformedURLException e) {
                log.debug("Unable to build resource filter provider.");
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected boolean isPreconditionValid(WebdavRequest request, DavResource resource) {
        return !resource.exists() || request.matchesIfHeader(resource);
    }

    /**
     * Returns the <code>DavLocatorFactory</code>. If no locator factory has
     * been set or created a new instance of {@link org.apache.jackrabbit.webdav.simple.LocatorFactoryImpl} is
     * returned.
     *
     * @return the locator factory
     * @see AbstractWebdavServlet#getLocatorFactory()
     */
    @Override
    public DavLocatorFactory getLocatorFactory() {
        if (locatorFactory == null) {
            locatorFactory = new LocatorFactoryImpl(resourcePathPrefix);
        }
        return locatorFactory;
    }

    /**
     * Sets the <code>DavLocatorFactory</code>.
     *
     * @param locatorFactory
     * @see AbstractWebdavServlet#setLocatorFactory(DavLocatorFactory)
     */
    @Override
    public void setLocatorFactory(DavLocatorFactory locatorFactory) {
        this.locatorFactory = locatorFactory;
    }

    /**
     * Returns the <code>DavResourceFactory</code>. If no request factory has
     * been set or created a new instance of {@link ResourceFactoryImpl} is
     * returned.
     *
     * @return the resource factory
     * @see org.apache.jackrabbit.server.AbstractWebdavServlet#getResourceFactory()
     */
    @Override
    public DavResourceFactory getResourceFactory() {
        if (resourceFactory == null) {
            resourceFactory = new FSDavResourceFactory(getResourceConfig(), getConf(getServletContext()));
        }
        return resourceFactory;
    }

    /**
     * Sets the <code>DavResourceFactory</code>.
     *
     * @param resourceFactory
     * @see AbstractWebdavServlet#setResourceFactory(org.apache.jackrabbit.webdav.DavResourceFactory)
     */
    @Override
    public void setResourceFactory(DavResourceFactory resourceFactory) {
        this.resourceFactory = resourceFactory;
    }

    /**
     * Returns the <code>DavSessionProvider</code>. If no session provider has
     * been set or created a new instance of {@link FakeDavSessionProvider}
     * is returned.
     *
     * @return the session provider
     */
    @Override
    public synchronized DavSessionProvider getDavSessionProvider() {
        if (davSessionProvider == null) {
            davSessionProvider = new FakeDavSessionProvider();
        }
        return davSessionProvider;
    }

    /**
     * Sets the <code>DavSessionProvider</code>.
     *
     * @param sessionProvider
     * @see AbstractWebdavServlet#setDavSessionProvider(org.apache.jackrabbit.webdav.DavSessionProvider)
     */
    @Override
    public synchronized void setDavSessionProvider(DavSessionProvider sessionProvider) {
        this.davSessionProvider = sessionProvider;
    }

    /**
     * Returns the header value retrieved from the {@link #INIT_PARAM_AUTHENTICATE_HEADER}
     * init parameter. If the parameter is missing, the value defaults to
     * {@link #DEFAULT_AUTHENTICATE_HEADER}.
     *
     * @return the header value retrieved from the corresponding init parameter
     * or {@link #DEFAULT_AUTHENTICATE_HEADER}.
     * @see org.apache.jackrabbit.server.AbstractWebdavServlet#getAuthenticateHeaderValue()
     */
    @Override
    public String getAuthenticateHeaderValue() {
        return authenticate_header;
    }

    /**
     * Returns the resource configuration to be applied
     *
     * @return the resource configuration.
     */
    private ResourceConfig getResourceConfig() {
        // fallback if no config present
        try {
            if (config == null) {
                config = new ResourceConfig(getDetector());
            }
        } catch (ServletException sv) {
        }
        return config;
    }

    /**
     * Returns the caches {@link Configuration} if a {@link Configuration} is 
     * found in the {@link javax.servlet.ServletContext} it is simply returned,
     * otherwise, a new {@link Configuration} is created, and then all the init 
     * parameters found in the {@link javax.servlet.ServletContext} are added to 
     * the {@link Configuration} (the created {@link Configuration} is then 
     * saved into the {@link javax.servlet.ServletContext}).
     *
     * @param application is the ServletContext whose init parameters
     *        must override those of Nutch.
     */

    //TODO for DEBUG only
    private static List<String> currentUserRoles;

    private static Configuration getConf(ServletContext application) {
        Configuration conf = (Configuration) application.getAttribute("dfs.servlet.conf.key");

        if (conf == null) {
            conf = hadoopConfig;
            Enumeration e = application.getInitParameterNames();
            while (e.hasMoreElements()) {
                String name = (String) e.nextElement();
                conf.set(name, application.getInitParameter(name));
            }
            application.setAttribute("dfs.servlet.conf.key", conf);
        }

        if (currentUserName != null) {
            WebAppContext webapp = (WebAppContext) application.getAttribute(WebdavServer.WEB_APP_CONTEXT);
            WebdavHashUserRealm userRealm = (WebdavHashUserRealm) webapp.getSecurityHandler().getUserRealm();
            List<String> userRoles = userRealm.getUserRoles(currentUserName);
            currentUserRoles = userRoles;

            UnixUserGroupInformation ugi = new UnixUserGroupInformation(currentUserName,
                    userRoles.toArray(new String[0]));
            UnixUserGroupInformation.saveToConf(conf, UnixUserGroupInformation.UGI_PROPERTY_NAME, ugi);
        }
        return conf;
    }

    private Detector getDetector() throws ServletException {
        URL url;

        String mimeInfo = getInitParameter(INIT_PARAM_MIME_INFO);
        if (mimeInfo != null) {
            try {
                url = getServletContext().getResource(mimeInfo);
            } catch (MalformedURLException e) {
                throw new ServletException(
                        "Invalid " + INIT_PARAM_MIME_INFO + " configuration setting: " + mimeInfo, e);
            }
        } else {
            url = MimeTypesFactory.class.getResource("tika-mimetypes.xml");
        }

        try {
            return MimeTypesFactory.create(url);
        } catch (MimeTypeException e) {
            throw new ServletException("Invalid MIME media type database: " + url, e);
        } catch (IOException e) {
            throw new ServletException("Unable to read MIME media type database: " + url, e);
        }
    }

    /**
     * This is a cheesy way to set the value of the hadoop config
     * @param config
     */
    public static void setConf(Configuration config) {
        hadoopConfig = config;
    }

    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        log.info("/--------------------------------------------------");
        log.debug(request.getMethod() + " " + request.getRequestURL().toString());
        log.info(request.getMethod() + " " + request.getRequestURL().toString());
        log.info(request.getMethod() + " " + request.getRequestURI().toString());

        log.info("  RemoteHost: " + request.getRemoteHost());
        log.info("| ATTRIBUTES: ");
        Enumeration e1 = request.getAttributeNames();
        while (e1.hasMoreElements()) {
            String name = (String) e1.nextElement();
            log.info("|| " + name + ": ");
        }

        log.info("| PARAMETERS: ");
        Enumeration e2 = request.getParameterNames();
        while (e2.hasMoreElements()) {
            String name = (String) e2.nextElement();
            log.info("|| " + name + ": ");
        }

        log.info("HEADERS: ");
        Enumeration e6 = request.getHeaderNames();
        while (e6.hasMoreElements()) {
            String name = (String) e6.nextElement();
            log.info("-- " + name + ": " + request.getHeader(name));
        }
        log.info("RemoteUser: " + request.getRemoteUser());
        log.info("AuthType: " + request.getAuthType());

        currentUserName = request.getRemoteUser();

        String roles = "";
        if (currentUserRoles != null) {
            for (String roleName : currentUserRoles) {
                roles += roleName + ", ";
            }
            if (roles.length() > 2) {
                roles = roles.substring(0, roles.length() - 2);
            }
        }
        log.debug("Roles: " + roles);

        try {
            super.service(request, response);
        } catch (Exception e) {
            if (e.getCause() instanceof AccessControlException) {
                log.info("EXCEPTION: Can't access to resource. You don't have permissions.");
                MultiStatusResponse msr = new MultiStatusResponse(request.getRequestURL().toString(), 401,
                        "Can't access to resource. You don't have permissions.");

                MultiStatus ms = new MultiStatus();
                ms.addResponse(msr);

                WebdavResponse webdavResponse = new WebdavResponseImpl(response);
                webdavResponse.sendMultiStatus(ms);
            } else
                new WebdavResponseImpl(response).sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }

        log.info("\\--------------------------------------------------");
    }
}