001/*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2008-2012 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * Sonar is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * Sonar is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public
017 * License along with Sonar; if not, write to the Free Software
018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
019 */
020package org.sonar.server.plugins;
021
022import com.google.common.annotations.VisibleForTesting;
023import org.apache.commons.io.IOUtils;
024import org.apache.commons.lang.StringUtils;
025import org.slf4j.Logger;
026import org.slf4j.LoggerFactory;
027import org.sonar.server.platform.Platform;
028
029import javax.servlet.ServletException;
030import javax.servlet.http.HttpServlet;
031import javax.servlet.http.HttpServletRequest;
032import javax.servlet.http.HttpServletResponse;
033import java.io.IOException;
034import java.io.InputStream;
035import java.io.OutputStream;
036
037public class StaticResourcesServlet extends HttpServlet {
038
039  private static final Logger LOG = LoggerFactory.getLogger(StaticResourcesServlet.class);
040  private static final long serialVersionUID = -2577454614650178426L;
041
042  @Override
043  public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
044    String pluginKey = getPluginKey(request);
045    String resource = getResourcePath(request);
046
047    DefaultServerPluginRepository pluginRepository = Platform.getInstance().getContainer().getComponentByType(DefaultServerPluginRepository.class);
048    ClassLoader classLoader = pluginRepository.getClassLoader(pluginKey);
049    if (classLoader == null) {
050      LOG.error("Plugin not found: " + pluginKey);
051      response.sendError(HttpServletResponse.SC_NOT_FOUND);
052      return;
053    }
054    InputStream in = null;
055    OutputStream out = null;
056    try {
057      in = classLoader.getResourceAsStream(resource);
058      if (in != null) {
059        out = response.getOutputStream();
060        IOUtils.copy(in, out);
061        completeContentType(response, resource);
062
063      } else {
064        LOG.error("Unable to find resource '" + resource + "' in plugin '" + pluginKey + "'");
065        response.sendError(HttpServletResponse.SC_NOT_FOUND);
066      }
067    } catch (Exception e) {
068      LOG.error("Unable to load static resource '" + resource + "' from plugin '" + pluginKey + "'", e);
069      response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
070    } finally {
071      IOUtils.closeQuietly(in);
072      IOUtils.closeQuietly(out);
073    }
074  }
075
076  /**
077   * @return part of request URL after servlet path
078   */
079  protected String getPluginKeyAndResourcePath(HttpServletRequest request) {
080    return StringUtils.substringAfter(request.getRequestURI(), request.getContextPath() + request.getServletPath() + "/");
081  }
082
083  protected String getPluginKey(HttpServletRequest request) {
084    return StringUtils.substringBefore(getPluginKeyAndResourcePath(request), "/");
085  }
086
087  /**
088   * Note that returned value should not have a leading "/" - see {@link Class#resolveName(String)}.
089   */
090  protected String getResourcePath(HttpServletRequest request) {
091    return "static/" + StringUtils.substringAfter(getPluginKeyAndResourcePath(request), "/");
092  }
093
094  @VisibleForTesting
095  void completeContentType(HttpServletResponse response, String filename) {
096    response.setContentType(MimeTypes.getByFilename(filename));
097  }
098}