001/*
002 * Shredzone Commons
003 *
004 * Copyright (C) 2012 Richard "Shred" Körber
005 *   http://commons.shredzone.org
006 *
007 * This program is free software: you can redistribute it and/or modify
008 * it under the terms of the GNU Library General Public License as
009 * published by the Free Software Foundation, either version 3 of the
010 * License, or (at your option) any later version.
011 *
012 * This program is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015 * GNU General Public License for more details.
016 *
017 * You should have received a copy of the GNU Library General Public License
018 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
019 */
020
021package org.shredzone.commons.view.servlet;
022
023import java.util.concurrent.atomic.AtomicReference;
024
025import javax.annotation.Nonnull;
026import javax.annotation.ParametersAreNonnullByDefault;
027import javax.servlet.ServletConfig;
028import javax.servlet.ServletException;
029import javax.servlet.http.HttpServletRequest;
030import javax.servlet.http.HttpServletResponse;
031
032import org.shredzone.commons.view.ViewService;
033import org.shredzone.commons.view.exception.ViewException;
034import org.slf4j.LoggerFactory;
035import org.springframework.web.servlet.FrameworkServlet;
036
037/**
038 * Main servlet for handling all kind of view requests.
039 *
040 * @author Richard "Shred" Körber
041 */
042@ParametersAreNonnullByDefault
043public class ViewServlet extends FrameworkServlet {
044    private static final long serialVersionUID = 6193053466721043404L;
045
046    private final AtomicReference<ViewService> viewService = new AtomicReference<>();
047
048    @Override
049    public void init(ServletConfig config) throws ServletException {
050        super.init(config);
051        getServletContext().setAttribute("jspPath", getJspPath(config));
052    }
053
054    @Override
055    protected void doService(HttpServletRequest req, HttpServletResponse resp) throws Exception {
056        try {
057            getViewService().handleRequest(req, resp);
058        } catch (ViewException ex) {
059            LoggerFactory.getLogger(getClass()).error("Failed to handle request", ex);
060            if (!resp.isCommitted()) {
061                resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getMessage()); //NOSONAR
062            }
063        }
064    }
065
066    /**
067     * Returns the {@link ViewService} singleton.
068     */
069    private @Nonnull ViewService getViewService() {
070        ViewService result = viewService.get();
071        if (result == null) {
072            result = getWebApplicationContext().getBean(ViewService.class);
073            viewService.compareAndSet(null, result);
074        }
075        return result;
076    }
077
078    /**
079     * Gets the JSP path from the servlet configuration. The default implementation
080     * fetches the value from the servlet's "jspPath" init parameter. Extending classes
081     * may override this method to fetch the configuration from somewhere else.
082     *
083     * @param config
084     *            {@link ServletConfig}
085     * @return JSP path, must end with a trailing '/'
086     */
087    protected @Nonnull String getJspPath(ServletConfig config) {
088        String jspPath = "/";
089        String path = config.getInitParameter("jspPath");
090        if (path != null) {
091            if (!path.endsWith("/")) {
092                path += "/";
093            }
094            jspPath = path;
095        }
096        return jspPath;
097    }
098
099}