Return-Path: X-Original-To: apmail-sling-commits-archive@www.apache.org Delivered-To: apmail-sling-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id F1B2A96D8 for ; Thu, 2 Feb 2012 10:29:21 +0000 (UTC) Received: (qmail 85725 invoked by uid 500); 2 Feb 2012 10:29:21 -0000 Delivered-To: apmail-sling-commits-archive@sling.apache.org Received: (qmail 85273 invoked by uid 500); 2 Feb 2012 10:29:15 -0000 Mailing-List: contact commits-help@sling.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@sling.apache.org Delivered-To: mailing list commits@sling.apache.org Received: (qmail 84610 invoked by uid 99); 2 Feb 2012 10:29:14 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 02 Feb 2012 10:29:14 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 02 Feb 2012 10:29:10 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id D88622388A67; Thu, 2 Feb 2012 10:28:50 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1239517 - in /sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl: ./ log/ request/ Date: Thu, 02 Feb 2012 10:28:50 -0000 To: commits@sling.apache.org From: fmeschbe@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20120202102850.D88622388A67@eris.apache.org> Author: fmeschbe Date: Thu Feb 2 10:28:49 2012 New Revision: 1239517 URL: http://svn.apache.org/viewvc?rev=1239517&view=rev Log: SLING-2389 Install request logging as a Servlet API filter to catch all requests - Add a new log parameter 'y' to emit the HttpServletRequest.getAuthType() - Refactor RequestLogger to register RequestLoggerService instances according to the request and access log configuration - RequestLoggerFilter is only active if at least one RequestLoggerService is registered - RequestLoggerFilter takes no configuration Added: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLoggerFilter.java sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLoggerRequest.java sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLoggerResponse.java Modified: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/SlingMainServlet.java sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/SlingRequestProcessorImpl.java sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/CustomLogFormat.java sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLogger.java sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLoggerService.java sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/request/RequestData.java Modified: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/SlingMainServlet.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/SlingMainServlet.java?rev=1239517&r1=1239516&r2=1239517&view=diff ============================================================================== --- sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/SlingMainServlet.java (original) +++ sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/SlingMainServlet.java Thu Feb 2 10:28:49 2012 @@ -56,7 +56,6 @@ import org.apache.sling.engine.SlingRequ import org.apache.sling.engine.impl.filter.ServletFilterManager; import org.apache.sling.engine.impl.helper.RequestListenerManager; import org.apache.sling.engine.impl.helper.SlingServletContext; -import org.apache.sling.engine.impl.log.RequestLogger; import org.apache.sling.engine.impl.parameters.ParameterSupport; import org.apache.sling.engine.impl.request.RequestData; import org.apache.sling.engine.impl.request.RequestHistoryConsolePlugin; @@ -82,7 +81,6 @@ import org.slf4j.LoggerFactory; }) @References( { @Reference(name = "ErrorHandler", referenceInterface = ErrorHandler.class, cardinality = ReferenceCardinality.OPTIONAL_UNARY, policy = ReferencePolicy.DYNAMIC, bind = "setErrorHandler", unbind = "unsetErrorHandler"), - @Reference(name = "RequestLogger", referenceInterface = RequestLogger.class, cardinality = ReferenceCardinality.OPTIONAL_UNARY, policy = ReferencePolicy.DYNAMIC, bind = "setRequestLogger", unbind = "unsetRequestLogger"), @Reference(name = "ServletResolver", referenceInterface = ServletResolver.class, cardinality = ReferenceCardinality.OPTIONAL_UNARY, policy = ReferencePolicy.DYNAMIC, bind = "setServletResolver", unbind = "unsetServletResolver"), @Reference(name = "MimeTypeService", referenceInterface = MimeTypeService.class, cardinality = ReferenceCardinality.OPTIONAL_UNARY, policy = ReferencePolicy.DYNAMIC, bind = "setMimeTypeService", unbind = "unsetMimeTypeService"), @Reference(name = "AuthenticationSupport", referenceInterface = AuthenticationSupport.class, cardinality = ReferenceCardinality.OPTIONAL_UNARY, policy = ReferencePolicy.DYNAMIC, bind = "setAuthenticationSupport", unbind = "unsetAuthenticationSupport") }) @@ -522,14 +520,6 @@ public class SlingMainServlet extends Ge requestProcessor.unsetServletResolver(servletResolver); } - public void setRequestLogger(final RequestLogger requestLogger) { - requestProcessor.setRequestLogger(requestLogger); - } - - public void unsetRequestLogger(final RequestLogger requestLogger) { - requestProcessor.unsetRequestLogger(requestLogger); - } - public void setMimeTypeService(final MimeTypeService mimeTypeService) { slingHttpContext.setMimeTypeService(mimeTypeService); } Modified: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/SlingRequestProcessorImpl.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/SlingRequestProcessorImpl.java?rev=1239517&r1=1239516&r2=1239517&view=diff ============================================================================== --- sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/SlingRequestProcessorImpl.java (original) +++ sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/SlingRequestProcessorImpl.java Thu Feb 2 10:28:49 2012 @@ -53,7 +53,6 @@ import org.apache.sling.engine.impl.filt 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.log.RequestLogger; import org.apache.sling.engine.impl.request.ContentData; import org.apache.sling.engine.impl.request.RequestData; import org.apache.sling.engine.impl.request.RequestHistoryConsolePlugin; @@ -72,8 +71,6 @@ public class SlingRequestProcessorImpl i private ErrorHandler errorHandler = defaultErrorHandler; - private RequestLogger requestLogger; - private ServletResolver servletResolver; private ServletFilterManager filterManager; @@ -96,16 +93,6 @@ public class SlingRequestProcessorImpl i } } - void setRequestLogger(final RequestLogger requestLogger) { - this.requestLogger = requestLogger; - } - - void unsetRequestLogger(final RequestLogger requestLogger) { - if (this.requestLogger == requestLogger) { - this.requestLogger = null; - } - } - void setServletResolver(final ServletResolver servletResolver) { this.servletResolver = servletResolver; } @@ -139,11 +126,6 @@ public class SlingRequestProcessorImpl i // record the request for the web console display RequestHistoryConsolePlugin.recordRequest(request); - // request entry log - if (requestLogger != null) { - requestLogger.logRequestEntry(request, response); - } - long startTimestamp = System.currentTimeMillis(); try { @@ -245,11 +227,6 @@ public class SlingRequestProcessorImpl i if (mbean != null) { mbean.addRequestDuration(elapsed); } - - // request exit log - if (requestLogger != null) { - requestLogger.logRequestExit(request, response); - } } } Modified: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/CustomLogFormat.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/CustomLogFormat.java?rev=1239517&r1=1239516&r2=1239517&view=diff ============================================================================== --- sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/CustomLogFormat.java (original) +++ sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/CustomLogFormat.java Thu Feb 2 10:28:49 2012 @@ -31,9 +31,8 @@ import java.util.Locale; import javax.servlet.http.Cookie; -import org.apache.sling.api.SlingHttpServletRequest; -import org.apache.sling.api.resource.Resource; -import org.apache.sling.engine.impl.SlingHttpServletResponseImpl; +import org.apache.sling.engine.impl.request.RequestData; +import org.osgi.service.http.HttpContext; /** * The CustomLogFormat class implements the support for log format @@ -73,9 +72,9 @@ class CustomLogFormat { * formatter has not been initialized with a valid log format * pattern. */ - String format(SlingHttpServletRequest request, SlingHttpServletResponseImpl response) { + String format(RequestLoggerRequest request, RequestLoggerResponse response) { if (this.logParameters != null) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); for (int i=0; i < this.logParameters.length; i++) { this.logParameters[i].print(buf, request, response); } @@ -273,6 +272,10 @@ class CustomLogFormat { param = new ServerNameParameter(); break; + case 'y': + param = new AuthTypeParameter(); + break; + case 'X': // no supported fall through to default case 'I': // no supported fall through to default case 'O': // no supported fall through to default @@ -280,12 +283,13 @@ class CustomLogFormat { case 'l': // no supported fall through to default case 'e': // no supported fall through to default default: - param = new NonImplementedParameter((char) c, name); + param = new NonImplementedParameter(name); break; } if (param instanceof BaseParameter) { BaseParameter baseParam = (BaseParameter) param; + baseParam.setParName((char) c); baseParam.setRequired(required); baseParam.setStatusLimits(statCodes); } @@ -346,7 +350,7 @@ class CustomLogFormat { //---------- Parameter support -------------------------------------------- static interface Parameter { - void print(StringBuffer dest, SlingHttpServletRequest request, SlingHttpServletResponseImpl response); + void print(StringBuilder dest, RequestLoggerRequest request, RequestLoggerResponse response); } static class PlainTextParameter implements Parameter { @@ -354,8 +358,8 @@ class CustomLogFormat { PlainTextParameter(String value) { this.value = value; } - public void print(StringBuffer dest, SlingHttpServletRequest request, - SlingHttpServletResponseImpl response) { + public void print(StringBuilder dest, RequestLoggerRequest request, + RequestLoggerResponse response) { dest.append(this.value); } public String toString() { @@ -366,23 +370,17 @@ class CustomLogFormat { abstract static class BaseParameter implements Parameter { private int[] statusLimits; private boolean required; - private final char parName; + private char parName; private final String parParam; - private final boolean isRequest; - protected BaseParameter(int[] statusLimits, boolean required, char parName, String parParam, boolean isRequest) { - this.statusLimits = statusLimits; - this.required = required; - this.parName = parName; + protected BaseParameter(String parParam, boolean isRequest) { this.parParam = parParam; this.isRequest = isRequest; } - protected BaseParameter(char parName, String parParam, boolean isRequest) { + public void setParName(char parName) { this.parName = parName; - this.parParam = parParam; - this.isRequest = isRequest; } public void setStatusLimits(int[] statusLimits) { @@ -393,10 +391,10 @@ class CustomLogFormat { this.required = required; } - protected abstract String getValue(SlingHttpServletRequest request); - protected abstract String getValue(SlingHttpServletResponseImpl response); + protected abstract String getValue(RequestLoggerRequest request); + protected abstract String getValue(RequestLoggerResponse response); - public final void print(StringBuffer dest, SlingHttpServletRequest request, SlingHttpServletResponseImpl response) { + public final void print(StringBuilder dest, RequestLoggerRequest request, RequestLoggerResponse response) { if (this.printOk(response.getStatus())) { String value = this.isRequest ? this.getValue(request) : this.getValue(response); dest.append((value == null) ? "-" : value); @@ -516,71 +514,71 @@ class CustomLogFormat { static class NonImplementedParameter extends BaseParameter { - NonImplementedParameter(char parName, String parParam) { - super(parName, parParam, true); + NonImplementedParameter(String parParam) { + super(parParam, true); } - protected String getValue(SlingHttpServletRequest request) { + protected String getValue(RequestLoggerRequest request) { return null; } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { return null; } } static class ThreadParameter extends BaseParameter { public ThreadParameter(String parParam) { - super('P', parParam, true); + super(parParam, true); } - protected String getValue(SlingHttpServletRequest request) { + protected String getValue(RequestLoggerRequest request) { return Thread.currentThread().getName(); } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { return null; } } static class ParamParameter extends BaseParameter { public ParamParameter(String parParam) { - super('M', parParam, true); + super(parParam, true); } - protected String getValue(SlingHttpServletRequest request) { + protected String getValue(RequestLoggerRequest request) { return request.getParameter(this.getParParam()); } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { return null; } } static class IdParameter extends BaseParameter { public IdParameter() { - super('R', null, false); + super(null, false); } - protected String getValue(SlingHttpServletRequest request) { + protected String getValue(RequestLoggerRequest request) { return null; } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { return String.valueOf(response.getRequestId()); } } static class ByteCountParameter extends BaseParameter { public ByteCountParameter(char c) { - super(c, null, false); + super(null, false); } - protected String getValue(SlingHttpServletRequest request) { + protected String getValue(RequestLoggerRequest request) { return null; } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { int count = response.getCount(); if (count == 0) { return (this.getParName() == 'b') ? "-" : "0"; @@ -615,16 +613,16 @@ class CustomLogFormat { private final boolean requestStart; public TimeParameter(String parParam) { - super('t', parParam, false); + super(parParam, false); this.requestStart = parParam== null || !parParam.equals("end"); } - protected String getValue(SlingHttpServletRequest request) { + protected String getValue(RequestLoggerRequest request) { return null; } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { long time = this.requestStart ? response.getRequestStart() : response.getRequestEnd(); return timeFormatted(time); } @@ -656,15 +654,15 @@ class CustomLogFormat { static class DurationParameter extends BaseParameter { private final boolean seconds; public DurationParameter(boolean seconds) { - super((seconds ? 'T' : 'D'), null, false); + super(null, false); this.seconds = seconds; } - protected String getValue(SlingHttpServletRequest request) { + protected String getValue(RequestLoggerRequest request) { return null; } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { long time = response.getRequestDuration(); if (this.seconds) { time /= 1000; @@ -675,95 +673,98 @@ class CustomLogFormat { static class RemoteIPParameter extends BaseParameter { public RemoteIPParameter() { - super('a', null, true); + super(null, true); } - protected String getValue(SlingHttpServletRequest request) { + protected String getValue(RequestLoggerRequest request) { return request.getRemoteAddr(); } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { return null; } } static class RemoteHostParameter extends BaseParameter { public RemoteHostParameter() { - super('h', null, true); + super(null, true); } - protected String getValue(SlingHttpServletRequest request) { + protected String getValue(RequestLoggerRequest request) { return request.getRemoteHost(); } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { return null; } } static class LocalIPParameter extends BaseParameter { public LocalIPParameter() { - super('A', null, true); + super(null, true); } - protected String getValue(SlingHttpServletRequest request) { + protected String getValue(RequestLoggerRequest request) { return request.getLocalAddr(); } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { return null; } } static class LocalPortParameter extends BaseParameter { public LocalPortParameter() { - super('p', null, true); + super(null, true); } - protected String getValue(SlingHttpServletRequest request) { + protected String getValue(RequestLoggerRequest request) { return String.valueOf(request.getServerPort()); } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { return null; } } static class ServerNameParameter extends BaseParameter { public ServerNameParameter() { - super('v', null, true); + super(null, true); } - protected String getValue(SlingHttpServletRequest request) { + protected String getValue(RequestLoggerRequest request) { return request.getServerName(); } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { return null; } } static class ContentPathParameter extends BaseParameter { public ContentPathParameter() { - super('f', null, true); + super(null, true); } - protected String getValue(SlingHttpServletRequest request) { - Resource resource = request.getResource(); - return (resource != null) ? resource.getPath() : null; + protected String getValue(RequestLoggerRequest request) { + final Object resourcePath = request.getAttribute(RequestData.REQUEST_RESOURCE_PATH_ATTR); + if (resourcePath instanceof String) { + return (String) resourcePath; + } + return null; } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { return null; } } static class FirstRequestLineParameter extends BaseParameter { public FirstRequestLineParameter() { - super('r', null, true); + super(null, true); } - protected String getValue(SlingHttpServletRequest request) { + protected String getValue(RequestLoggerRequest request) { String query = request.getQueryString(); query = (query == null || query.length() == 0) ? "" : "?" + query; @@ -771,92 +772,116 @@ class CustomLogFormat { + " " + request.getProtocol(); } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { return null; } } static class ProtocolParameter extends BaseParameter { public ProtocolParameter() { - super('H', null, true); + super(null, true); } - protected String getValue(SlingHttpServletRequest request) { + protected String getValue(RequestLoggerRequest request) { return request.getProtocol(); } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { return null; } } static class MethodParameter extends BaseParameter { public MethodParameter() { - super('m', null, true); + super(null, true); } - protected String getValue(SlingHttpServletRequest request) { + protected String getValue(RequestLoggerRequest request) { return request.getMethod(); } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { return null; } } static class RequestParameter extends BaseParameter { public RequestParameter() { - super('U', null, true); + super(null, true); } - protected String getValue(SlingHttpServletRequest request) { + protected String getValue(RequestLoggerRequest request) { return request.getRequestURI(); } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { return null; } } static class QueryParameter extends BaseParameter { public QueryParameter() { - super('q', null, true); + super(null, true); } - protected String getValue(SlingHttpServletRequest request) { + protected String getValue(RequestLoggerRequest request) { String query = request.getQueryString(); return (query == null || query.length() == 0) ? "" : "?" + query; } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { return null; } } static class UserParameter extends BaseParameter { public UserParameter() { - super('u', null, true); + super(null, true); } - protected String getValue(SlingHttpServletRequest request) { + protected String getValue(RequestLoggerRequest request) { + final Object user = request.getAttribute(HttpContext.REMOTE_USER); + if (user instanceof String) { + return (String) user; + } + return request.getRemoteUser(); } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { + return null; + } + } + + static class AuthTypeParameter extends BaseParameter { + public AuthTypeParameter() { + super(null, true); + } + + protected String getValue(RequestLoggerRequest request) { + final Object authType = request.getAttribute(HttpContext.AUTHENTICATION_TYPE); + if (authType instanceof String) { + return (String) authType; + } + + return request.getAuthType(); + } + + protected String getValue(RequestLoggerResponse response) { return null; } } static class StatusParameter extends BaseParameter { public StatusParameter() { - super('s', null, false); + super(null, false); } - protected String getValue(SlingHttpServletRequest request) { + protected String getValue(RequestLoggerRequest request) { return null; } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { return String.valueOf(response.getStatus()); } } @@ -864,16 +889,24 @@ class CustomLogFormat { static class CookieParameter extends BaseParameter { private String cookieName; CookieParameter(String cookieName, boolean isRequest) { - super('C', cookieName, isRequest); + super(cookieName, isRequest); this.cookieName = cookieName; } - protected String getValue(SlingHttpServletRequest request) { - Cookie cookie = request.getCookie(cookieName); - return (cookie == null) ? null : escape(cookie.toString()); + protected String getValue(RequestLoggerRequest request) { + final Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (int i = 0; i < cookies.length; i++) { + if (cookies[i].getName().equals(cookieName)) { + return escape(cookies[i].toString()); + } + } + } + + return null; } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { Cookie cookie = response.getCookie(this.cookieName); return (cookie == null) ? null : escape(cookie.toString()); } @@ -883,11 +916,11 @@ class CustomLogFormat { static class HeaderParameter extends BaseParameter { private String headerName; HeaderParameter(String headerName, boolean isRequest) { - super((isRequest ? 'i' : 'o'), headerName, isRequest); + super(headerName, isRequest); this.headerName = headerName; } - protected String getValue(SlingHttpServletRequest request) { + protected String getValue(RequestLoggerRequest request) { Enumeration values = request.getHeaders(this.headerName); if (values == null || !values.hasMoreElements()) { return null; @@ -900,7 +933,7 @@ class CustomLogFormat { return escape(value); } - protected String getValue(SlingHttpServletResponseImpl response) { + protected String getValue(RequestLoggerResponse response) { return escape(response.getHeaders(this.headerName)); } } Modified: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLogger.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLogger.java?rev=1239517&r1=1239516&r2=1239517&view=diff ============================================================================== --- sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLogger.java (original) +++ sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLogger.java Thu Feb 2 10:28:49 2012 @@ -18,21 +18,17 @@ */ package org.apache.sling.engine.impl.log; -import java.util.Dictionary; +import java.util.HashMap; import java.util.Hashtable; +import java.util.Map; +import java.util.Map.Entry; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Properties; import org.apache.felix.scr.annotations.Property; import org.apache.felix.scr.annotations.PropertyOption; -import org.apache.felix.scr.annotations.Reference; -import org.apache.felix.scr.annotations.ReferenceCardinality; -import org.apache.felix.scr.annotations.ReferencePolicy; -import org.apache.felix.scr.annotations.Service; -import org.apache.sling.api.SlingHttpServletRequest; -import org.apache.sling.api.SlingHttpServletResponse; -import org.apache.sling.engine.impl.SlingHttpServletResponseImpl; import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; /** * The RequestLogger is a request level filter, which @@ -42,16 +38,11 @@ import org.osgi.framework.BundleContext; * acting just before the request handling terminates. * */ -@Component(immediate=true,metatype=true,label="%request.log.name",description="%request.log.description") +@Component(metatype=true,label="%request.log.name",description="%request.log.description") @Properties({ @Property(name="service.description",value="Request Logger"), @Property(name="service.vendor",value="The Apache Software Foundation") }) -@Service(value=RequestLogger.class) -@Reference(name="RequestLoggerService", - referenceInterface=RequestLoggerService.class, - cardinality=ReferenceCardinality.OPTIONAL_MULTIPLE, - policy=ReferencePolicy.DYNAMIC) public class RequestLogger { @Property(value="logs/request.log") @@ -100,20 +91,6 @@ public class RequestLogger { private static final String ACCESS_LOG_FORMAT = "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""; /** - * The list of {@link RequestLoggerService} called when the request enters - * processing. The order of the services in this list determined by the - * registration order. - */ - private RequestLoggerService[] requestEntry; - - /** - * The list of {@link RequestLoggerService} called when the request is about - * to exit processing. The order of the services in this list determined by - * the registration order. - */ - private RequestLoggerService[] requestExit; - - /** * A special request logger service, which writes the request log message at * request start time. This logger logs a message with the format * {@link #REQUEST_LOG_ENTRY_FORMAT}. @@ -134,33 +111,11 @@ public class RequestLogger { */ private RequestLoggerService accessLog; - public void logRequestEntry(SlingHttpServletRequest request, SlingHttpServletResponse response) { - - if (response instanceof SlingHttpServletResponseImpl) { - // log the request start - if (this.requestEntry != null) { - for (int i = 0; i < this.requestEntry.length; i++) { - this.requestEntry[i].log(request, - (SlingHttpServletResponseImpl) response); - } - } - } - } - - public void logRequestExit(SlingHttpServletRequest request, SlingHttpServletResponse response) { - // signal the end of the request - if (response instanceof SlingHttpServletResponseImpl) { - SlingHttpServletResponseImpl loggerResponse = (SlingHttpServletResponseImpl) response; - loggerResponse.requestEnd(); - - // log the request end - if (this.requestExit != null) { - for (int i = 0; i < this.requestExit.length; i++) { - this.requestExit[i].log(request, loggerResponse); - } - } - } - } + /** + * RequestLoggerService instances created on behalf of the static + * configuration. + */ + private Map services = new HashMap(); // ---------- SCR Integration ---------------------------------------------- @@ -174,16 +129,7 @@ public class RequestLogger { * @param osgiContext The OSGi Component Context providing the configuration * data and access into the system. */ - protected void activate( - org.osgi.service.component.ComponentContext osgiContext) { - - BundleContext bundleContext = osgiContext.getBundleContext(); - @SuppressWarnings("unchecked") - Dictionary props = osgiContext.getProperties(); - - // initialize the FileRequestLog with sling.home as the root for - // relative log file paths - FileRequestLog.init(bundleContext.getProperty("sling.home")); + protected void activate(BundleContext bundleContext, Map props) { // prepare the request loggers if a name is configured and the // request loggers are enabled @@ -191,31 +137,20 @@ public class RequestLogger { Object requestLogEnabled = props.get(PROP_REQUEST_LOG_ENABLED); if (requestLogName != null && requestLogEnabled instanceof Boolean && ((Boolean) requestLogEnabled).booleanValue()) { - Object requestLogType = props.get(PROP_REQUEST_LOG_OUTPUT_TYPE); - - this.requestLogEntry = this.createRequestLoggerService(bundleContext, true, - REQUEST_LOG_ENTRY_FORMAT, requestLogName, requestLogType); - this.requestLogExit = this.createRequestLoggerService(bundleContext, false, - REQUEST_LOG_EXIT_FORMAT, requestLogName, requestLogType); - - this.bindRequestLoggerService(this.requestLogEntry); - this.bindRequestLoggerService(this.requestLogExit); + createRequestLoggerService(services, bundleContext, true, REQUEST_LOG_ENTRY_FORMAT, requestLogName, + requestLogType); + createRequestLoggerService(services, bundleContext, false, REQUEST_LOG_EXIT_FORMAT, requestLogName, + requestLogType); } // prepare the access logger if a name is configured and the // access logger is enabled Object accessLogName = props.get(PROP_ACCESS_LOG_OUTPUT); Object accessLogEnabled = props.get(PROP_ACCESS_LOG_ENABLED); - if (accessLogName != null && accessLogEnabled instanceof Boolean - && ((Boolean) accessLogEnabled).booleanValue()) { - + if (accessLogName != null && accessLogEnabled instanceof Boolean && ((Boolean) accessLogEnabled).booleanValue()) { Object accessLogType = props.get(PROP_ACCESS_LOG_OUTPUT_TYPE); - - this.accessLog = this.createRequestLoggerService(bundleContext, false, - ACCESS_LOG_FORMAT, accessLogName, accessLogType); - - this.bindRequestLoggerService(this.accessLog); + createRequestLoggerService(services, bundleContext, false, ACCESS_LOG_FORMAT, accessLogName, accessLogType); } } @@ -228,60 +163,12 @@ public class RequestLogger { * @param osgiContext The OSGi Component Context providing the configuration * data and access into the system. */ - protected void deactivate( - org.osgi.service.component.ComponentContext osgiContext) { - - // remove the loggers if they have been set up - if (this.requestLogEntry != null) { - this.unbindRequestLoggerService(this.requestLogEntry); - this.requestLogEntry.shutdown(); - this.requestLogEntry = null; - } - if (this.requestLogExit != null) { - this.unbindRequestLoggerService(this.requestLogExit); - this.requestLogExit.shutdown(); - this.requestLogExit = null; - } - if (this.accessLog != null) { - this.unbindRequestLoggerService(this.accessLog); - this.accessLog.shutdown(); - this.accessLog = null; - } - - // hack to ensure all log files are closed - FileRequestLog.dispose(); - } - - /** - * Binds a RequestLoggerService to be used during request - * filter. - * - * @param requestLoggerService The RequestLoggerService to - * use. - */ - protected void bindRequestLoggerService( - RequestLoggerService requestLoggerService) { - if (requestLoggerService.isOnEntry()) { - this.requestEntry = this.addService(this.requestEntry, requestLoggerService); - } else { - this.requestExit = this.addService(this.requestExit, requestLoggerService); - } - } - - /** - * Binds a RequestLoggerService to be used during request - * filter. - * - * @param requestLoggerService The RequestLoggerService to - * use. - */ - protected void unbindRequestLoggerService( - RequestLoggerService requestLoggerService) { - if (requestLoggerService.isOnEntry()) { - this.requestEntry = this.removeService(this.requestEntry, requestLoggerService); - } else { - this.requestExit = this.removeService(this.requestExit, requestLoggerService); + protected void deactivate() { + for (Entry entry : services.entrySet()) { + entry.getKey().unregister(); + entry.getValue().shutdown(); } + services.clear(); } /** @@ -306,82 +193,16 @@ public class RequestLogger { * @return The functional and prepared RequestLoggerService * instance. */ - private RequestLoggerService createRequestLoggerService( - BundleContext bundleContext, boolean onEntry, Object format, - Object output, Object outputType) { + private static void createRequestLoggerService(Map services, + BundleContext bundleContext, boolean onEntry, Object format, Object output, Object outputType) { final Hashtable config = new Hashtable(); - config.put(RequestLoggerService.PARAM_ON_ENTRY, onEntry - ? Boolean.TRUE - : Boolean.FALSE); + config.put(RequestLoggerService.PARAM_ON_ENTRY, onEntry ? Boolean.TRUE : Boolean.FALSE); config.put(RequestLoggerService.PARAM_FORMAT, format); config.put(RequestLoggerService.PARAM_OUTPUT, output); config.put(RequestLoggerService.PARAM_OUTPUT_TYPE, outputType); - return new RequestLoggerService(bundleContext, config); + final RequestLoggerService service = new RequestLoggerService(bundleContext, config); + final ServiceRegistration reg = bundleContext.registerService(service.getClass().getName(), service, config); + services.put(reg, service); } - - /** - * Creates a new list of request logger services from the existing list - * appending the new logger. This method does not check, whether the logger - * has already been added or not and so may add the the logger multiple - * times. It is the responsibility of the caller to make sure to not add - * services multiple times. - * - * @param list The list to add the new service to - * @param requestLoggerService The service to append to the list - * @param A new list with the added service at the end. - */ - private RequestLoggerService[] addService(RequestLoggerService[] list, - RequestLoggerService requestLoggerService) { - if (list == null) { - return new RequestLoggerService[] { requestLoggerService }; - } - - // add the service to the list, must not be in the list yet due to - // the SCR contract - RequestLoggerService[] newList = new RequestLoggerService[list.length + 1]; - System.arraycopy(list, 0, newList, 0, list.length); - newList[list.length] = requestLoggerService; - - return newList; - } - - /** - * Creates a new list of request logger services from the existing list by - * removing the named logger. The logger is searched for by referential - * equality (comparing the object references) and not calling the - * equals method. If the last element is being removed from - * the list, null is returned instead of an empty list. - * - * @param list The list from which the service is to be removed. - * @param requestLoggerService The service to remove. - * @return The list without the service. This may be the same list if the - * service is not in the list or may be null if the - * last service has just been removed from the list. - */ - private RequestLoggerService[] removeService(RequestLoggerService[] list, - RequestLoggerService requestLoggerService) { - - RequestLoggerService[] newList = null; - for (int i = 0; list != null && i < list.length; i++) { - if (list[i] == requestLoggerService) { - newList = new RequestLoggerService[list.length - 1]; - - // if not first take over the leading elements - if (i > 0) { - System.arraycopy(list, 0, newList, 0, i); - } - - // if not the last element, shift rest to the left - if (i < list.length - 1) { - System.arraycopy(list, i + 1, newList, 0, newList.length - - i); - } - } - } - - // return the new list if at least one entry is contained - return (newList != null && newList.length > 0) ? newList : null; - } - } Added: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLoggerFilter.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLoggerFilter.java?rev=1239517&view=auto ============================================================================== --- sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLoggerFilter.java (added) +++ sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLoggerFilter.java Thu Feb 2 10:28:49 2012 @@ -0,0 +1,238 @@ +/* + * 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.log; + +import java.io.IOException; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.ConfigurationPolicy; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Properties; +import org.apache.felix.scr.annotations.Property; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.apache.felix.scr.annotations.ReferencePolicy; +import org.apache.felix.scr.annotations.Service; +import org.osgi.framework.BundleContext; + +/** + * The RequestLogger is a request level filter, which + * provides customizable logging or requests handled by Sling. This filter is + * inserted as the first filter in the request level filter chain and therefore + * is the first filter called when processing a request and the last filter + * acting just before the request handling terminates. + * + */ +@Component(immediate = true, policy = ConfigurationPolicy.IGNORE) +@Properties({ + @Property(name = "service.description", value = "Request Logger Filter"), + @Property(name = "service.vendor", value = "The Apache Software Foundation") +}) +@Service(value = Filter.class) +@Reference( + name = "RequestLoggerService", + referenceInterface = RequestLoggerService.class, + cardinality = ReferenceCardinality.MANDATORY_MULTIPLE, + policy = ReferencePolicy.DYNAMIC) +@Property(name = "pattern", value = "/.*") +public final class RequestLoggerFilter implements Filter { + + private static final RequestLoggerService[] NONE = new RequestLoggerService[0]; + + /** + * The list of {@link RequestLoggerService} called when the request enters + * processing. The order of the services in this list determined by the + * registration order. + */ + private RequestLoggerService[] requestEntry = NONE; + + /** + * The list of {@link RequestLoggerService} called when the request is about + * to exit processing. The order of the services in this list determined by + * the registration order. + */ + private RequestLoggerService[] requestExit = NONE; + + public void init(FilterConfig filterConfig) { + } + + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, + ServletException { + + final RequestLoggerRequest rlreq = new RequestLoggerRequest((HttpServletRequest) request); + final RequestLoggerResponse rlres = new RequestLoggerResponse((HttpServletResponse) response); + + log(this.requestEntry, rlreq, rlres); + try { + chain.doFilter(rlreq, rlres); + } finally { + rlres.requestEnd(); + log(this.requestExit, rlreq, rlres); + } + } + + public void destroy() { + } + + // ---------- SCR Integration ---------------------------------------------- + + /** + * Activates this component by setting up the special request entry and exit + * request loggers and the access logger as configured in the context + * properties. In addition the FileRequestLog class is + * initialized with the value of the sling.home context + * property to resolve relative log file names. + */ + @Activate + @SuppressWarnings("unused") + private void activate(BundleContext bundleContext) { + + // initialize the FileRequestLog with sling.home as the root for + // relative log file paths + FileRequestLog.init(bundleContext.getProperty("sling.home")); + + } + + /** + * Deactivates this component by unbinding and shutting down all loggers + * setup during activation and finally dispose off the + * FileRequestLog class to make sure all shared writers are + * closed. + */ + @Deactivate + @SuppressWarnings("unused") + private void deactivate() { + // hack to ensure all log files are closed + FileRequestLog.dispose(); + } + + /** + * Binds a RequestLoggerService to be used during request + * filter. + * + * @param requestLoggerService The RequestLoggerService to + * use. + */ + @SuppressWarnings("unused") + private void bindRequestLoggerService( + RequestLoggerService requestLoggerService) { + if (requestLoggerService.isOnEntry()) { + this.requestEntry = this.addService(this.requestEntry, requestLoggerService); + } else { + this.requestExit = this.addService(this.requestExit, requestLoggerService); + } + } + + /** + * Binds a RequestLoggerService to be used during request + * filter. + * + * @param requestLoggerService The RequestLoggerService to + * use. + */ + @SuppressWarnings("unused") + private void unbindRequestLoggerService( + RequestLoggerService requestLoggerService) { + if (requestLoggerService.isOnEntry()) { + this.requestEntry = this.removeService(this.requestEntry, requestLoggerService); + } else { + this.requestExit = this.removeService(this.requestExit, requestLoggerService); + } + } + + /** + * Creates a new list of request logger services from the existing list + * appending the new logger. This method does not check, whether the logger + * has already been added or not and so may add the the logger multiple + * times. It is the responsibility of the caller to make sure to not add + * services multiple times. + * + * @param list The list to add the new service to + * @param requestLoggerService The service to append to the list + * @param A new list with the added service at the end. + */ + private RequestLoggerService[] addService(RequestLoggerService[] list, + RequestLoggerService requestLoggerService) { + if (list == NONE) { + return new RequestLoggerService[] { requestLoggerService }; + } + + // add the service to the list, must not be in the list yet due to + // the SCR contract + RequestLoggerService[] newList = new RequestLoggerService[list.length + 1]; + System.arraycopy(list, 0, newList, 0, list.length); + newList[list.length] = requestLoggerService; + + return newList; + } + + /** + * Creates a new list of request logger services from the existing list by + * removing the named logger. The logger is searched for by referential + * equality (comparing the object references) and not calling the + * equals method. If the last element is being removed from + * the list, NONE is returned instead of an empty list. + * + * @param list The list from which the service is to be removed. + * @param requestLoggerService The service to remove. + * @return The list without the service. This may be the same list if the + * service is not in the list or may be NONE if the + * last service has just been removed from the list. + */ + private RequestLoggerService[] removeService(RequestLoggerService[] list, + RequestLoggerService requestLoggerService) { + + RequestLoggerService[] newList = NONE; + for (int i = 0; i < list.length; i++) { + if (list[i] == requestLoggerService) { + newList = new RequestLoggerService[list.length - 1]; + + // if not first take over the leading elements + if (i > 0) { + System.arraycopy(list, 0, newList, 0, i); + } + + // if not the last element, shift rest to the left + if (i < list.length - 1) { + System.arraycopy(list, i + 1, newList, 0, newList.length + - i); + } + } + } + + // return the new list if at least one entry is contained + return (newList.length > 0) ? newList : NONE; + } + + private void log(RequestLoggerService[] services, final RequestLoggerRequest request, + final RequestLoggerResponse response) { + for (int i = 0; i < services.length; i++) { + services[i].log(request, response); + } + } +} Added: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLoggerRequest.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLoggerRequest.java?rev=1239517&view=auto ============================================================================== --- sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLoggerRequest.java (added) +++ sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLoggerRequest.java Thu Feb 2 10:28:49 2012 @@ -0,0 +1,30 @@ +/* + * 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.log; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + +class RequestLoggerRequest extends HttpServletRequestWrapper { + + RequestLoggerRequest(HttpServletRequest request) { + super(request); + } + +} Added: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLoggerResponse.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLoggerResponse.java?rev=1239517&view=auto ============================================================================== --- sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLoggerResponse.java (added) +++ sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLoggerResponse.java Thu Feb 2 10:28:49 2012 @@ -0,0 +1,428 @@ +/* + * 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.log; + +import java.io.IOException; +import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; + +public class RequestLoggerResponse extends HttpServletResponseWrapper { + + // the content type header name + private static final String HEADER_CONTENT_TYPE = "Content-Type"; + + // the content length header name + private static final String HEADER_CONTENT_LENGTH = "Content-Length"; + + /** format for RFC 1123 date string -- "Sun, 06 Nov 1994 08:49:37 GMT" */ + private final static SimpleDateFormat RFC1123_FORMAT = new SimpleDateFormat( + "EEE, dd MMM yyyy HH:mm:ss z", Locale.US); + + /** + * The counter for request gone through this filter. As this is the first + * request level filter hit, this counter should actually count each request + * which at least enters the request level component filter processing. + *

+ * This counter is reset to zero, when this component is activated. That is, + * each time this component is restarted (system start, bundle start, + * reconfiguration), the request counter restarts at zero. + */ + private static AtomicLong requestCounter = new AtomicLong(); + + // TODO: more content related headers, namely Content-Language should + // probably be supported + + // the request counter + private long requestId; + + // the system time in ms when the request entered the system, this is + // the time this instance was created + private long requestStart; + + // the system time in ms when the request exited the system, this is + // the time of the call to the requestEnd() method + private long requestEnd; + + // the output stream wrapper providing the transferred byte count + private LoggerResponseOutputStream out; + + // the print writer wrapper providing the transferred character count + private LoggerResponseWriter writer; + + // the caches status + private int status = SC_OK; + + // the cookies set during the request, indexed by cookie name + private Map cookies; + + // the headers set during the request, indexed by lower-case header + // name, value is string for single-valued and list for multi-valued + // headers + private Map headers; + + public RequestLoggerResponse(HttpServletResponse response) { + super(response); + + this.requestId = requestCounter.getAndIncrement(); + this.requestStart = System.currentTimeMillis(); + } + + /** + * Called to indicate the request processing has ended. This method + * currently sets the request end time returned by {@link #getRequestEnd()} + * and which is used to calculate the request duration. + */ + public void requestEnd() { + this.requestEnd = System.currentTimeMillis(); + } + +// protected final RequestData getRequestData() { +// return requestData; +// } + + //---------- SlingHttpServletResponse interface + + @Override + public ServletOutputStream getOutputStream() throws IOException { + if (this.out == null) { + ServletOutputStream sos = getResponse().getOutputStream(); + this.out = new LoggerResponseOutputStream(sos); + } + return this.out; + } + + @Override + public PrintWriter getWriter() throws IOException { + if (this.writer == null) { + PrintWriter pw = getResponse().getWriter(); + this.writer = new LoggerResponseWriter(pw); + } + return this.writer; + } + + // ---------- Error handling through Sling Error Resolver ----------------- + + + @Override + public void sendRedirect(String location) throws IOException { + super.sendRedirect(location); + + // replicate the status code of call to base class + this.status = SC_MOVED_TEMPORARILY; + } + + @Override + public void sendError(int status) throws IOException { + super.sendError(status); + this.status = status; + } + + @Override + public void sendError(int status, String message) throws IOException { + super.sendError(status, message); + this.status = status; + } + + @Override + public void setStatus(int status, String message) { + super.setStatus(status, message); + this.status = status; + } + + @Override + public void setStatus(int status) { + super.setStatus(status); + this.status = status; + } + + public void addCookie(Cookie cookie) { + + // register the cookie for later use + if (this.cookies == null) { + this.cookies = new HashMap(); + } + this.cookies.put(cookie.getName(), cookie); + + super.addCookie(cookie); + } + + public void addDateHeader(String name, long date) { + this.registerHeader(name, toDateString(date), true); + super.addDateHeader(name, date); + } + + public void addHeader(String name, String value) { + this.registerHeader(name, value, true); + super.addHeader(name, value); + } + + public void addIntHeader(String name, int value) { + this.registerHeader(name, String.valueOf(value), true); + super.addIntHeader(name, value); + } + + public void setContentLength(int len) { + this.registerHeader(HEADER_CONTENT_LENGTH, String.valueOf(len), false); + super.setContentLength(len); + } + + public void setContentType(String type) { + // SLING-726 No handling required since this seems to be correct + this.registerHeader(HEADER_CONTENT_TYPE, type, false); + super.setContentType(type); + } + + @Override + public void setCharacterEncoding(String charset) { + // SLING-726 Ignore call if getWriter() has been called + if (writer == null) { + super.setCharacterEncoding(charset); + } + } + + public void setDateHeader(String name, long date) { + this.registerHeader(name, toDateString(date), false); + super.setDateHeader(name, date); + } + + public void setHeader(String name, String value) { + this.registerHeader(name, value, false); + super.setHeader(name, value); + } + + public void setIntHeader(String name, int value) { + this.registerHeader(name, String.valueOf(value), false); + this.setHeader(name, String.valueOf(value)); + } + + public void setLocale(Locale loc) { + // TODO: Might want to register the Content-Language header + super.setLocale(loc); + } + + // ---------- Retrieving response information ------------------------------ + + public long getRequestId() { + return this.requestId; + } + + public long getRequestStart() { + return this.requestStart; + } + + public long getRequestEnd() { + return this.requestEnd; + } + + public long getRequestDuration() { + return this.requestEnd - this.requestStart; + } + + public int getStatus() { + return this.status; + } + + public int getCount() { + if (this.out != null) { + return this.out.getCount(); + } else if (this.writer != null) { + return this.writer.getCount(); + } + + // otherwise return zero + return 0; + } + + public Cookie getCookie(String name) { + return (this.cookies != null) ? (Cookie) this.cookies.get(name) : null; + } + + public String getHeaders(String name) { + // normalize header name to lower case to support case-insensitive + // headers + name = name.toLowerCase(); + + Object header = (this.headers != null) ? this.headers.get(name) : null; + if (header == null) { + return null; + } else if (header instanceof String) { + return (String) header; + } else { + StringBuffer headerBuf = new StringBuffer(); + for (Iterator hi = ((List) header).iterator(); hi.hasNext();) { + if (headerBuf.length() > 0) { + headerBuf.append(","); + } + headerBuf.append(hi.next()); + } + return headerBuf.toString(); + } + } + + // ---------- Internal helper --------------------------------------------- + + /** + * Stores the name header-value pair in the header map. The name is + * converted to lower-case before using it as an index in the map. + * + * @param name The name of the header to register + * @param value The value of the header to register + * @param add If true the header value is added to the list + * of potentially existing header values. Otherwise the new value + * replaces any existing values. + */ + @SuppressWarnings("unchecked") + private void registerHeader(String name, String value, boolean add) { + // ensure the headers map + if (this.headers == null) { + this.headers = new HashMap(); + } + + // normalize header name to lower case to support case-insensitive + // headers + name = name.toLowerCase(); + + // retrieve the current contents if adding, otherwise assume no current + Object current = add ? this.headers.get(name) : null; + + if (current == null) { + // set the single value (forced if !add) + this.headers.put(name, value); + + } else if (current instanceof String) { + // create list if a single value is already set + List list = new ArrayList(); + list.add((String) current); + list.add(value); + this.headers.put(name, list); + + } else { + // append to the list of more than one already set + ((List) current).add(value); + } + } + + /** + * Converts the time value given as the number of milliseconds since January + * 1, 1970 to a date and time string compliant with RFC 1123 date + * specification. The resulting string is compliant with section 3.3.1, Full + * Date, of RFC 2616 + * and may thus be used as the value of date header such as + * Date. + * + * @param date The date value to convert to a string + * @return The string representation of the date and time value. + */ + public static String toDateString(long date) { + synchronized (RFC1123_FORMAT) { + return RFC1123_FORMAT.format(new Date(date)); + } + } + + //---------- byte/character counting output channels ---------------------- + + // byte transfer counting ServletOutputStream + private static class LoggerResponseOutputStream extends ServletOutputStream { + private ServletOutputStream delegatee; + + private int count; + + LoggerResponseOutputStream(ServletOutputStream delegatee) { + this.delegatee = delegatee; + } + + public int getCount() { + return this.count; + } + + public void write(int b) throws IOException { + this.delegatee.write(b); + this.count++; + } + + public void write(byte[] b) throws IOException { + this.delegatee.write(b); + this.count += b.length; + } + + public void write(byte[] b, int off, int len) throws IOException { + this.delegatee.write(b, off, len); + this.count += len; + } + + public void flush() throws IOException { + this.delegatee.flush(); + } + + public void close() throws IOException { + this.delegatee.close(); + } + } + + // character transfer counting PrintWriter + private static class LoggerResponseWriter extends PrintWriter { + + private static final int LINE_SEPARATOR_LENGTH = System.getProperty( + "line.separator").length(); + + private int count; + + LoggerResponseWriter(PrintWriter delegatee) { + super(delegatee); + } + + public int getCount() { + return this.count; + } + + public void write(int c) { + super.write(c); + this.count++; + } + + public void write(char[] buf, int off, int len) { + super.write(buf, off, len); + this.count += len; + } + + public void write(String s, int off, int len) { + super.write(s, off, len); + this.count += len; + } + + public void println() { + super.println(); + this.count += LINE_SEPARATOR_LENGTH; + } + } + +} Modified: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLoggerService.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLoggerService.java?rev=1239517&r1=1239516&r2=1239517&view=diff ============================================================================== --- sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLoggerService.java (original) +++ sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/log/RequestLoggerService.java Thu Feb 2 10:28:49 2012 @@ -19,19 +19,18 @@ package org.apache.sling.engine.impl.log; import java.io.IOException; -import java.util.Dictionary; +import java.util.Map; +import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.ConfigurationPolicy; +import org.apache.felix.scr.annotations.Deactivate; import org.apache.felix.scr.annotations.Properties; import org.apache.felix.scr.annotations.Property; import org.apache.felix.scr.annotations.PropertyOption; import org.apache.felix.scr.annotations.Service; -import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.engine.RequestLog; -import org.apache.sling.engine.impl.SlingHttpServletResponseImpl; import org.osgi.framework.BundleContext; -import org.osgi.service.component.ComponentContext; /** * The RequestLoggerService is a factory component which gets @@ -83,11 +82,12 @@ public class RequestLoggerService { public RequestLoggerService() { } - RequestLoggerService(BundleContext bundleContext, Dictionary configuration) { + RequestLoggerService(BundleContext bundleContext, Map configuration) { this.setup(bundleContext, configuration); } - void setup(BundleContext bundleContext, Dictionary configuration) { + @Activate + void setup(BundleContext bundleContext, Map configuration) { // whether to log on request entry or request exit Object onEntryObject = configuration.get(PARAM_ON_ENTRY); this.onEntry = (onEntryObject instanceof Boolean) @@ -111,6 +111,7 @@ public class RequestLoggerService { } } + @Deactivate void shutdown() { if (this.log != null) { this.log.close(); @@ -120,7 +121,7 @@ public class RequestLoggerService { this.logFormat = null; } - void log(SlingHttpServletRequest request, SlingHttpServletResponseImpl response) { + void log(RequestLoggerRequest request, RequestLoggerResponse response) { if (this.log != null && this.logFormat != null) { this.log.write(this.logFormat.format(request, response)); } @@ -130,17 +131,6 @@ public class RequestLoggerService { return this.onEntry; } - // ---------- SCR integration ---------------------------------------------- - - @SuppressWarnings("unchecked") - protected void activate(ComponentContext context) { - this.setup(context.getBundleContext(), context.getProperties()); - } - - protected void deactivate(ComponentContext context) { - this.shutdown(); - } - private RequestLog getLog(BundleContext bundleContext, String output, int outputType) { switch (outputType) { Modified: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/request/RequestData.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/request/RequestData.java?rev=1239517&r1=1239516&r2=1239517&view=diff ============================================================================== --- sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/request/RequestData.java (original) +++ sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/request/RequestData.java Thu Feb 2 10:28:49 2012 @@ -83,6 +83,12 @@ public class RequestData { public static final int DEFAULT_MAX_CALL_COUNTER = 1000; /** + * The name of the request attribute providing the resource addressed by the + * request URL. + */ + public static final String REQUEST_RESOURCE_PATH_ATTR = "$$sling.request.resource$$"; + + /** * The maximum inclusion depth (default * {@link #DEFAULT_MAX_INCLUSION_COUNTER}). This value is compared to the * number of entries in the {@link #contentDataStack} when the @@ -192,6 +198,9 @@ public class RequestData { requestProgressTracker.startTimer("ResourceResolution"); final SlingHttpServletRequest request = getSlingRequest(); Resource resource = resourceResolver.resolve(request, request.getPathInfo()); + if (request.getAttribute(REQUEST_RESOURCE_PATH_ATTR) == null) { + request.setAttribute(REQUEST_RESOURCE_PATH_ATTR, resource.getPath()); + } requestProgressTracker.logTimer("ResourceResolution", "URI={0} resolves to Resource={1}", getServletRequest().getRequestURI(), resource);