uk.ac.cam.caret.sakai.rwiki.access.WikiAccessServlet.java Source code

Java tutorial

Introduction

Here is the source code for uk.ac.cam.caret.sakai.rwiki.access.WikiAccessServlet.java

Source

/**********************************************************************************
 * $URL: https://source.sakaiproject.org/svn/rwiki/trunk/rwiki-access-tool/src/java/uk/ac/cam/caret/sakai/rwiki/access/WikiAccessServlet.java $ 
 * $Id: WikiAccessServlet.java 51318 2008-08-24 05:28:47Z csev@umich.edu $
 ***********************************************************************************
 *
 * Copyright (c) 2006, 2008 Sakai Foundation
 *
 * Licensed under the Educational Community 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.opensource.org/licenses/ECL-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 uk.ac.cam.caret.sakai.rwiki.access;

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.entity.api.EntityAccessOverloadException;
import org.sakaiproject.entity.api.EntityNotDefinedException;
import org.sakaiproject.entity.api.EntityPermissionException;
import org.sakaiproject.entity.api.EntityProducer;
import org.sakaiproject.entity.api.HttpAccess;
import org.sakaiproject.entity.api.Reference;
import org.sakaiproject.entity.cover.EntityManager;
import org.sakaiproject.tool.api.ActiveTool;
import org.sakaiproject.tool.api.Session;
import org.sakaiproject.tool.api.Tool;
import org.sakaiproject.tool.api.ToolException;
import org.sakaiproject.tool.cover.ActiveToolManager;
import org.sakaiproject.tool.cover.SessionManager;
import org.sakaiproject.util.BasicAuth;
import org.sakaiproject.util.Validator;
import org.sakaiproject.util.Web;

/**
 * <p>
 * Wiki extends access: all references are assumed to be under "/wiki/site"
 * </p>
 * 
 * @author Sakai Software Development Team
 */
public class WikiAccessServlet extends HttpServlet {
    /** Our log (commons). */
    private static Log M_log = LogFactory.getLog(WikiAccessServlet.class);

    protected BasicAuth basicAuth = null;

    /**
     * initialize the AccessServlet servlet
     * 
     * @param config
     *        the servlet config parameter
     * @exception ServletException
     *            in case of difficulties
     */
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        basicAuth = new BasicAuth();
        basicAuth.init();

    }

    /**
     * Set active session according to sessionId parameter
     */
    private void setSession(HttpServletRequest req) {
        String sessionId = req.getParameter("session");
        if (sessionId != null) {
            Session session = SessionManager.getSession(sessionId);

            if (session != null) {
                session.setActive();
                SessionManager.setCurrentSession(session);
            }
        }
    }

    /**
     * respond to an HTTP GET request
     * 
     * @param req
     *          HttpServletRequest object with the client request
     * @param res
     *          HttpServletResponse object back to the client
     * @exception ServletException
     *              in case of difficulties
     * @exception IOException
     *              in case of difficulties
     */
    public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        setSession(req);
        dispatch(req, res);
    }

    /**
     * handle get and post communication from the user
     * 
     * @param req
     *        HttpServletRequest object with the client request
     * @param res
     *        HttpServletResponse object back to the client
     */
    public void dispatch(HttpServletRequest req, HttpServletResponse res) throws ServletException {

        long start = System.currentTimeMillis();

        req.setAttribute(Tool.NATIVE_URL, Tool.NATIVE_URL);

        // get the path info
        String path = req.getPathInfo();
        req.setAttribute(Tool.NATIVE_URL, null);
        if (path == null)
            path = "";

        // pre-process the path
        String origPath = path;
        path = preProcessPath(path, req);

        // what is being requested?
        Reference ref = EntityManager.newReference(path);

        // let the entity producer handle it
        try {
            // make sure we have a valid reference with an entity producer we can talk to
            EntityProducer service = ref.getEntityProducer();
            if (service == null)
                throw new EntityNotDefinedException(ref.getReference());

            // get the producer's HttpAccess helper, it might not support one
            HttpAccess access = service.getHttpAccess();
            if (access == null)
                throw new EntityNotDefinedException(ref.getReference());

            // let the helper do the work
            access.handleAccess(req, res, ref, null);
        } catch (EntityNotDefinedException e) {
            // the request was not valid in some way
            sendError(res, HttpServletResponse.SC_NOT_FOUND);
            return;
        } catch (EntityPermissionException e) {
            // the end user does not have permission - offer a login if there is no user id yet established
            // if not permitted, and the user is the anon user, let them login
            if (SessionManager.getCurrentSessionUserId() == null) {
                try {
                    doLogin(req, res, origPath);
                } catch (IOException ioex) {
                }
                return;
            }

            // otherwise reject the request
            sendError(res, HttpServletResponse.SC_FORBIDDEN);
        } catch (EntityAccessOverloadException e) {
            M_log.info("dispatch(): ref: " + ref.getReference() + e);
            sendError(res, HttpServletResponse.SC_SERVICE_UNAVAILABLE);
        } catch (Throwable e) {
            M_log.warn("dispatch(): exception: ", e);
            sendError(res, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }

        finally {
            long end = System.currentTimeMillis();

            // log
            if (M_log.isDebugEnabled())
                M_log.debug("from:" + req.getRemoteAddr() + " path:" + origPath + " options: "
                        + req.getQueryString() + " time: " + (end - start));
        }
    }

    /**
     * respond to an HTTP POST request; only to handle the login process
     * 
     * @param req
     *        HttpServletRequest object with the client request
     * @param res
     *        HttpServletResponse object back to the client
     * @exception ServletException
     *            in case of difficulties
     * @exception IOException
     *            in case of difficulties
     */
    public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        req.setAttribute(Tool.NATIVE_URL, Tool.NATIVE_URL);
        // catch the login helper posts
        String option = req.getPathInfo();
        req.setAttribute(Tool.NATIVE_URL, null);
        String[] parts = option.split("/");
        if ((parts.length == 2) && (("login".equals(parts[1])))) {
            doLogin(req, res, null);
        } else {
            sendError(res, HttpServletResponse.SC_NOT_FOUND);
        }
    }

    /**
     * Make any changes needed to the path before final "ref" processing.
     * 
     * @param path
     *        The path from the request.
     * @param req
     *        The request object.
     * @return The path to use to make the Reference for further processing.
     */
    protected String preProcessPath(String path, HttpServletRequest req) {
        // everything we work with is down the "content" part of the Sakai access URL space

        // if path is just "/", we don't really know if the request was to .../SERVLET or .../SERVLET/ - we want to preserve the trailing slash
        // the request URI will tell us
        if ("/".equals(path) && !(req.getRequestURI().endsWith("/"))) {
            return "/wiki";
        } else {
            // to relax the URL: allow /wiki/site/siteId and also allow /wiki/siteId
            if (path.startsWith("/site/")) {
                return "/wiki" + path;
            } else {
                return "/wiki/site" + path;
            }
        }
    }

    /**
     * Make a redirect to the login url.
     * 
     * @param req
     *        HttpServletRequest object with the client request.
     * @param res
     *        HttpServletResponse object back to the client.
     * @param path
     *        The current request path, set ONLY if we want this to be where to redirect the user after successfull login
     * @throws IOException 
     */
    protected void doLogin(HttpServletRequest req, HttpServletResponse res, String path)
            throws ToolException, IOException {
        // if basic auth is valid do that
        if (basicAuth.doAuth(req, res)) {
            //System.err.println("BASIC Auth Request Sent to the Browser ");
            return;
        }

        // get the Sakai session
        Session session = SessionManager.getCurrentSession();

        // set the return path for after login if needed (Note: in session, not tool session, special for Login helper)
        if (path != null) {
            // where to go after
            String returnPath = Web.returnUrl(req, Validator.escapeUrl(path));
            session.setAttribute(Tool.HELPER_DONE_URL, returnPath);
        }

        // check that we have a return path set; might have been done earlier
        if (session.getAttribute(Tool.HELPER_DONE_URL) == null) {
            M_log.error("doLogin - proceeding with null HELPER_DONE_URL");
        }

        // map the request to the helper, leaving the path after ".../options" for the helper
        ActiveTool tool = ActiveToolManager.getActiveTool("sakai.login");
        String context = req.getContextPath() + req.getServletPath() + "/login";
        tool.help(req, res, context, "/login");
    }

    protected void sendError(HttpServletResponse res, int code) {
        try {
            res.sendError(code);
        } catch (Throwable t) {
            M_log.warn("sendError: " + t);
        }
    }

}