Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * 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.sling.engine.impl;
- import static org.apache.sling.api.SlingConstants.ERROR_SERVLET_NAME;
- import java.io.IOException;
- import java.io.OutputStream;
- import java.io.OutputStreamWriter;
- import java.io.PrintWriter;
- import java.io.Writer;
- import java.security.AccessControlException;
- import javax.servlet.FilterChain;
- import javax.servlet.Servlet;
- import javax.servlet.ServletException;
- import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
- import javax.servlet.UnavailableException;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.servlet.http.HttpServletResponseWrapper;
- import javax.jcr.Session;
- import org.apache.sling.api.SlingException;
- import org.apache.sling.api.SlingHttpServletRequest;
- import org.apache.sling.api.SlingHttpServletResponse;
- import org.apache.sling.api.SlingServletException;
- import org.apache.sling.api.request.RequestPathInfo;
- import org.apache.sling.api.resource.Resource;
- import org.apache.sling.api.resource.ResourceNotFoundException;
- import org.apache.sling.api.resource.ResourceResolver;
- import org.apache.sling.api.servlets.ServletResolver;
- import org.apache.sling.api.wrappers.SlingHttpServletResponseWrapper;
- import org.apache.sling.commons.metrics.Histogram;
- import org.apache.sling.commons.metrics.MetricsService;
- import org.apache.sling.engine.SlingRequestProcessor;
- import org.apache.sling.engine.impl.filter.AbstractSlingFilterChain;
- import org.apache.sling.engine.impl.filter.FilterHandle;
- import org.apache.sling.engine.impl.filter.RequestSlingFilterChain;
- import org.apache.sling.engine.impl.filter.ServletFilterManager;
- import org.apache.sling.engine.impl.filter.ServletFilterManager.FilterChainType;
- import org.apache.sling.engine.impl.filter.SlingComponentFilterChain;
- import org.apache.sling.engine.impl.parameters.ParameterSupport;
- import org.apache.sling.engine.impl.request.ContentData;
- import org.apache.sling.engine.impl.request.RequestData;
- import org.apache.sling.engine.impl.request.RequestHistoryConsolePlugin;
- import org.apache.sling.engine.servlets.ErrorHandler;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- public class SlingRequestProcessorImpl implements SlingRequestProcessor {
- /** default log */
- private final Logger log = LoggerFactory.getLogger(SlingRequestProcessorImpl.class);
- // used fields ....
- private MetricsService metricsService;
- private Histogram histogram;
- SlingRequestProcessorImpl (MetricsService metricsService) {
- this.metricsService = metricsService;
- histogram = metricsService.histogram("engine.main.histogram-Filter-in-Chain");
- }
- private final DefaultErrorHandler errorHandler = new DefaultErrorHandler();
- private ServletResolver servletResolver;
- private ServletFilterManager filterManager;
- private RequestProcessorMBeanImpl mbean;
- // ---------- helper setters
- void setServerInfo(final String serverInfo) {
- errorHandler.setServerInfo(serverInfo);
- }
- void setErrorHandler(final ErrorHandler eh) {
- errorHandler.setDelegate(eh);
- }
- void unsetErrorHandler(final ErrorHandler eh) {
- if (errorHandler.getDelegate() == eh) {
- errorHandler.setDelegate(null);
- }
- }
- void setServletResolver(final ServletResolver servletResolver) {
- this.servletResolver = servletResolver;
- }
- void unsetServletResolver(final ServletResolver servletResolver) {
- if (this.servletResolver == servletResolver) {
- this.servletResolver = null;
- }
- }
- void setFilterManager(final ServletFilterManager filterManager) {
- this.filterManager = filterManager;
- }
- void setMBean(final RequestProcessorMBeanImpl mbean) {
- this.mbean = mbean;
- }
- /**
- * Wrap an HttpServletRequest to generate metrics
- * mesuring the request per second of each HTTP
- * request to a session and the authentication Type*/
- private void getSessionUser(SlingHttpServletRequest request){
- Resource resource = request.getResource();
- if(resource != null){
- String sessionUser = resource.adaptTo(Session.class).getUserID();
- if(sessionUser == null){
- metricsService.counter("engine.main.count-Authenticated-Request").increment();
- } else {
- metricsService.counter("engine.main.count-Anonymous-Request").increment();
- }
- }
- }
- /**
- * This method is directly called by the Sling main servlet.
- */
- public void doProcessRequest(final HttpServletRequest servletRequest,
- final HttpServletResponse originalServlet,
- final ResourceResolver resourceResolver) throws IOException {
- final HttpServletResponse servletResponse = new MetricsResponseWrapper(originalServlet);
- // setting the Sling request and response
- final RequestData requestData = new RequestData(this, servletRequest,
- servletResponse);
- final SlingHttpServletRequest request = requestData.getSlingRequest();
- final SlingHttpServletResponse response = requestData.getSlingResponse();
- getSessionUser(request);
- RequestHistoryConsolePlugin.recordRequest(request);
- try {
- final ServletResolver sr = this.servletResolver;
- // check that we have all required services
- if (resourceResolver == null) {
- throw new UnavailableException("ResourceResolver");
- } else if (sr == null) {
- throw new UnavailableException("ServletResolver");
- }
- // initialize the request data - resolve resource and servlet
- Resource resource = requestData.initResource(resourceResolver);
- requestData.initServlet(resource, sr);
- FilterHandle[] filters = filterManager.getFilters(FilterChainType.REQUEST);
- if (filters != null) {
- histogram.update(filters.length);
- FilterChain processor = new RequestSlingFilterChain(this,
- filters);
- request.getRequestProgressTracker().log(
- "Applying " + FilterChainType.REQUEST + "filters");
- processor.doFilter(request, response);
- } else {
- // no filters, directly call resource level filters and servlet
- processComponent(request, response, FilterChainType.COMPONENT);
- }
- } catch ( final SlingHttpServletResponseImpl.WriterAlreadyClosedException wace ) {
- log.error("Writer has already been closed.", wace);
- } catch (ResourceNotFoundException rnfe) {
- // send this exception as a 404 status
- log.info("service: Resource {} not found", rnfe.getResource());
- handleError(HttpServletResponse.SC_NOT_FOUND, rnfe.getMessage(),
- request, response);
- } catch (final SlingException se) {
- // if we have request data and a non-null F servlet name
- // we assume, that this is the name of the causing servlet
- if (requestData.getActiveServletName() != null) {
- request.setAttribute(ERROR_SERVLET_NAME,
- requestData.getActiveServletName());
- }
- // send this exception as is (albeit unwrapping and wrapped
- // exception.
- Throwable t = se;
- while ( t instanceof SlingException && t.getCause() != null ) {
- t = t.getCause();
- }
- log.error("service: Uncaught SlingException", t);
- handleError(t, request, response);
- } catch (AccessControlException ace) {
- // SLING-319 if anything goes wrong, send 403/FORBIDDEN
- log.info(
- "service: Authenticated user {} does not have enough rights to executed requested action",
- request.getRemoteUser());
- handleError(HttpServletResponse.SC_FORBIDDEN, null, request,
- response);
- } catch (UnavailableException ue) {
- // exception is thrown before the SlingHttpServletRequest/Response
- // is properly set up due to missing dependencies. In this case
- // we must not use the Sling error handling infrastructure but
- // just return a 503 status response handled by the servlet
- // container environment
- final int status = HttpServletResponse.SC_SERVICE_UNAVAILABLE;
- final String errorMessage = ue.getMessage()
- + " service missing, cannot service requests";
- log.error("{} , sending status {}", errorMessage, status);
- servletResponse.sendError(status, errorMessage);
- } catch (IOException ioe) {
- // forward IOException up the call chain to properly handle it
- throw ioe;
- } catch (Throwable t) {
- // if we have request data and a non-null active servlet name
- // we assume, that this is the name of the causing servlet
- if (requestData.getActiveServletName() != null) {
- request.setAttribute(ERROR_SERVLET_NAME,
- requestData.getActiveServletName());
- }
- log.error("service: Uncaught Throwable", t);
- handleError(t, request, response);
- } finally {
- if (mbean != null) {
- mbean.addRequestData(requestData);
- }
- }
- }
- // ---------- SlingRequestProcessor interface
- /**
- * @see org.apache.sling.engine.SlingRequestProcessor#processRequest(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.apache.sling.api.resource.ResourceResolver)
- */
- public void processRequest(final HttpServletRequest servletRequest,
- final HttpServletResponse servletResponse,
- final ResourceResolver resourceResolver) throws IOException {
- // set the marker for the parameter support
- final Object oldValue = servletRequest.getAttribute(ParameterSupport.MARKER_IS_SERVICE_PROCESSING);
- servletRequest.setAttribute(ParameterSupport.MARKER_IS_SERVICE_PROCESSING, Boolean.TRUE);
- try {
- this.doProcessRequest(servletRequest, servletResponse, resourceResolver);
- } finally {
- // restore the old value
- if ( oldValue != null ) {
- servletRequest.setAttribute(ParameterSupport.MARKER_IS_SERVICE_PROCESSING, oldValue);
- } else {
- servletRequest.removeAttribute(ParameterSupport.MARKER_IS_SERVICE_PROCESSING);
- }
- }
- }
- /**
- * Renders the component defined by the RequestData's current ComponentData
- * instance after calling all filters of the given
- * {@link org.apache.sling.engine.impl.filter.ServletFilterManager.FilterChainType
- * filterChainType}.
- *
- * @param request
- * @param response
- * @param filterChainType
- * @throws IOException
- * @throws ServletException
- */
- public void processComponent(SlingHttpServletRequest request,
- SlingHttpServletResponse response,
- final FilterChainType filterChainType) throws IOException,
- ServletException {
- FilterHandle filters[] = filterManager.getFilters(filterChainType);
- if (filters != null) {
- FilterChain processor = new SlingComponentFilterChain(filters);
- request.getRequestProgressTracker().log(
- "Applying " + filterChainType + "filters");
- processor.doFilter(request, response);
- } else {
- log.debug("service: No Resource level filters, calling servlet");
- RequestData.service(request, response);
- }
- }
- // ---------- Generic Content Request processor ----------------------------
- /**
- * Dispatches the request on behalf of the
- * {@link org.apache.sling.engine.impl.request.SlingRequestDispatcher}.
- */
- public void dispatchRequest(ServletRequest request,
- ServletResponse response, Resource resource,
- RequestPathInfo resolvedURL, boolean include) throws IOException,
- ServletException {
- // we need a SlingHttpServletRequest/SlingHttpServletResponse tupel
- // to continue
- SlingHttpServletRequest cRequest = RequestData.toSlingHttpServletRequest(request);
- SlingHttpServletResponse cResponse = RequestData.toSlingHttpServletResponse(response);
- // get the request data (and btw check the correct type)
- final RequestData requestData = RequestData.getRequestData(cRequest);
- final ContentData oldContentData = requestData.getContentData();
- final ContentData contentData = requestData.setContent(resource, resolvedURL);
- try {
- // resolve the servlet
- Servlet servlet = servletResolver.resolveServlet(cRequest);
- contentData.setServlet(servlet);
- FilterChainType type = include
- ? FilterChainType.INCLUDE
- : FilterChainType.FORWARD;
- processComponent(cRequest, cResponse, type);
- } finally {
- requestData.resetContent(oldContentData);
- }
- }
- // ---------- Error Handling with Filters
- void handleError(final int status, final String message,
- final SlingHttpServletRequest request,
- SlingHttpServletResponse response) throws IOException {
- // wrap the response ensuring getWriter will fall back to wrapping
- // the response output stream if reset does not reset this
- response = new ErrorResponseWrapper(response);
- FilterHandle[] filters = filterManager.getFilters(FilterChainType.ERROR);
- if (filters != null && filters.length > 0) {
- FilterChain processor = new AbstractSlingFilterChain(filters) {
- @Override
- protected void render(SlingHttpServletRequest request,
- SlingHttpServletResponse response) throws IOException {
- errorHandler.handleError(status, message, request, response);
- }
- };
- request.getRequestProgressTracker().log(
- "Applying " + FilterChainType.ERROR + " filters");
- try {
- processor.doFilter(request, response);
- } catch (ServletException se) {
- throw new SlingServletException(se);
- }
- } else {
- errorHandler.handleError(status, message, request, response);
- }
- }
- // just rethrow the exception as explained in the class comment
- private void handleError(final Throwable throwable,
- final SlingHttpServletRequest request,
- SlingHttpServletResponse response) throws IOException {
- // wrap the response ensuring getWriter will fall back to wrapping
- // the response output stream if reset does not reset this
- response = new ErrorResponseWrapper(response);
- FilterHandle[] filters = filterManager.getFilters(FilterChainType.ERROR);
- if (filters != null && filters.length > 0) {
- FilterChain processor = new AbstractSlingFilterChain(filters) {
- @Override
- protected void render(SlingHttpServletRequest request,
- SlingHttpServletResponse response) throws IOException {
- errorHandler.handleError(throwable, request, response);
- }
- };
- request.getRequestProgressTracker().log(
- "Applying " + FilterChainType.ERROR + " filters");
- try {
- processor.doFilter(request, response);
- } catch (ServletException se) {
- throw new SlingServletException(se);
- }
- } else {
- errorHandler.handleError(throwable, request, response);
- }
- }
- /**Wrap an HttpSerletResponse to generate metrics counting and mesuring the request per second of each HTTP
- * response status code*/
- private class MetricsResponseWrapper extends HttpServletResponseWrapper{
- MetricsResponseWrapper(HttpServletResponse servletResponse) {
- super(servletResponse);
- }
- private void computeMetrics(int statusCode) {
- if(metricsService == null) {
- log.warn("Missing MetricsService, cannot compute metrics for status {}", statusCode);
- return;
- }
- metricsService.counter("engine.main.count." + statusCode).increment();
- metricsService.meter("engine.main.mark"+statusCode).mark();
- }
- @Override
- public void sendError(int statusCode) throws IOException {
- computeMetrics(statusCode);
- super.sendError(statusCode);
- }
- @Override
- public void sendError(int sc, String msg) throws IOException {
- computeMetrics(sc);
- super.sendError(sc, msg);
- }
- @Override
- public void setStatus(int sc) {
- computeMetrics(sc);
- super.setStatus(sc);
- }
- @Override
- public void setStatus(int sc, String sm) {
- computeMetrics(sc);
- super.setStatus(sc, sm);
- }
- }
- private static class ErrorResponseWrapper extends
- SlingHttpServletResponseWrapper {
- private PrintWriter writer;
- public ErrorResponseWrapper(SlingHttpServletResponse wrappedResponse) {
- super(wrappedResponse);
- }
- @Override
- public PrintWriter getWriter() throws IOException {
- if (writer == null) {
- try {
- writer = super.getWriter();
- } catch (IllegalStateException ise) {
- // resetting the response did not reset the output channel
- // status and we have to create a writer based on the output
- // stream using the character encoding already set on the
- // response, defaulting to ISO-8859-1
- OutputStream out = getOutputStream();
- String encoding = getCharacterEncoding();
- if (encoding == null) {
- encoding = "ISO-8859-1";
- setCharacterEncoding(encoding);
- }
- Writer w = new OutputStreamWriter(out, encoding);
- writer = new PrintWriter(w);
- }
- }
- return writer;
- }
- /**
- * Flush the writer if the {@link #getWriter()} method was called
- * to potentially wrap an OuputStream still existing in the response.
- */
- @Override
- public void flushBuffer() throws IOException {
- if (writer != null) {
- writer.flush();
- }
- super.flushBuffer();
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement