SLING-11515 : Provide interface to get the recent requests
diff --git a/src/main/java/org/apache/sling/engine/RequestInfo.java b/src/main/java/org/apache/sling/engine/RequestInfo.java
new file mode 100644
index 0000000..428209e
--- /dev/null
+++ b/src/main/java/org/apache/sling/engine/RequestInfo.java
@@ -0,0 +1,60 @@
+/*
+ * 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;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Information about a single request.
+ * @see RequestInfoProvider
+ * @since 2.5
+ */
+public interface RequestInfo {
+
+ /**
+ * Get the unique id for the request
+ * @return The id
+ */
+ @NotNull String getId();
+
+ /**
+ * Get the request method
+ * @return The request method
+ */
+ @NotNull String getMethod();
+
+ /**
+ * Get the requested path
+ * @return The path
+ */
+ @NotNull String getPath();
+
+ /**
+ * Get the user id for the request
+ * @return the user id or {@code null}
+ */
+ @Nullable String getUserId();
+
+ /**
+ * Get the log for the request
+ * @return The request log, multi-line output
+ */
+ @NotNull String getLog();
+}
diff --git a/src/main/java/org/apache/sling/engine/RequestInfoProvider.java b/src/main/java/org/apache/sling/engine/RequestInfoProvider.java
new file mode 100644
index 0000000..27441e3
--- /dev/null
+++ b/src/main/java/org/apache/sling/engine/RequestInfoProvider.java
@@ -0,0 +1,52 @@
+/*
+ * 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;
+
+/**
+ * This service can be used to gather information about requests processed by the
+ * engine.
+ *
+ * @since 2.5
+ */
+ public interface RequestInfoProvider {
+
+ /**
+ * Get the request info for the id
+ * @param id The id
+ * @return The request info or {@code null}
+ */
+ RequestInfo getRequestInfo(String id);
+
+ /**
+ * Get the request infos
+ * @return An iterator for the request infos
+ */
+ Iterable<RequestInfo> getRequestInfos();
+
+ /**
+ * Get the maximum number of provided infos
+ * @return The maximum number, {@code 0} if no infos are recorded
+ */
+ int getMayNumberOfInfos();
+
+ /**
+ * Clear all request infos
+ */
+ void clear();
+ }
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/engine/impl/SlingMainServlet.java b/src/main/java/org/apache/sling/engine/impl/SlingMainServlet.java
index d1e3add..eabc7eb 100644
--- a/src/main/java/org/apache/sling/engine/impl/SlingMainServlet.java
+++ b/src/main/java/org/apache/sling/engine/impl/SlingMainServlet.java
@@ -42,6 +42,7 @@
import org.apache.sling.commons.mime.MimeTypeService;
import org.apache.sling.engine.SlingRequestProcessor;
import org.apache.sling.engine.impl.console.RequestHistoryConsolePlugin;
+import org.apache.sling.engine.impl.debug.RequestInfoProviderImpl;
import org.apache.sling.engine.impl.filter.ServletFilterManager;
import org.apache.sling.engine.impl.helper.ClientAbortException;
import org.apache.sling.engine.impl.helper.RequestListenerManager;
@@ -116,7 +117,7 @@
"internally recorded for display on the \"Recent Requests\" Web Console page. If " +
"this value is less than or equal to zero, no requests are internally kept. The " +
"default value is 20. ")
- int sling_max_record_requests() default RequestHistoryConsolePlugin.STORED_REQUESTS_COUNT;
+ int sling_max_record_requests() default RequestInfoProviderImpl.STORED_REQUESTS_COUNT;
@AttributeDefinition(name = "Recorded Request Path Patterns",
description = "One or more regular expressions which " +
diff --git a/src/main/java/org/apache/sling/engine/impl/SlingRequestProcessorImpl.java b/src/main/java/org/apache/sling/engine/impl/SlingRequestProcessorImpl.java
index 63b1458..8337d5a 100644
--- a/src/main/java/org/apache/sling/engine/impl/SlingRequestProcessorImpl.java
+++ b/src/main/java/org/apache/sling/engine/impl/SlingRequestProcessorImpl.java
@@ -48,6 +48,7 @@
import org.apache.sling.api.wrappers.SlingHttpServletResponseWrapper;
import org.apache.sling.engine.SlingRequestProcessor;
import org.apache.sling.engine.impl.console.RequestHistoryConsolePlugin;
+import org.apache.sling.engine.impl.debug.RequestInfoProviderImpl;
import org.apache.sling.engine.impl.filter.AbstractSlingFilterChain;
import org.apache.sling.engine.impl.filter.FilterHandle;
import org.apache.sling.engine.impl.filter.RequestSlingFilterChain;
@@ -123,9 +124,6 @@
final SlingHttpServletRequest request = requestData.getSlingRequest();
final SlingHttpServletResponse response = requestData.getSlingResponse();
- // record the request for the web console display
- RequestHistoryConsolePlugin.recordRequest(request);
-
try {
final ServletResolver sr = this.servletResolver;
@@ -226,6 +224,9 @@
handleError(t, request, response);
} finally {
+ // record the request for the web console and info provider
+ RequestInfoProviderImpl.recordRequest(request);
+
if (mbean != null) {
mbean.addRequestData(requestData);
}
diff --git a/src/main/java/org/apache/sling/engine/impl/console/RequestHistoryConsolePlugin.java b/src/main/java/org/apache/sling/engine/impl/console/RequestHistoryConsolePlugin.java
index bfc3c71..c6d6fa5 100644
--- a/src/main/java/org/apache/sling/engine/impl/console/RequestHistoryConsolePlugin.java
+++ b/src/main/java/org/apache/sling/engine/impl/console/RequestHistoryConsolePlugin.java
@@ -21,12 +21,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
import java.util.List;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.regex.Pattern;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
@@ -34,15 +29,13 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.sling.api.SlingHttpServletRequest;
-import org.apache.sling.api.request.RequestProgressTracker;
import org.apache.sling.api.request.ResponseUtil;
import org.apache.sling.api.resource.ResourceUtil;
-import org.apache.sling.engine.impl.SlingMainServlet;
+import org.apache.sling.engine.RequestInfo;
+import org.apache.sling.engine.RequestInfoProvider;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.Deactivate;
-import org.osgi.service.component.annotations.Modified;
+import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.propertytypes.ServiceDescription;
import org.osgi.service.component.propertytypes.ServiceVendor;
@@ -52,7 +45,6 @@
* useful when testing or explaining things.
*/
@Component(service = Servlet.class,
- configurationPid = SlingMainServlet.PID,
property = {
"felix.webconsole.label=" + RequestHistoryConsolePlugin.LABEL,
"felix.webconsole.title=Recent requests",
@@ -70,104 +62,32 @@
public static final String CLEAR = "clear";
- private static volatile RequestHistoryConsolePlugin instance;
-
- public static final int STORED_REQUESTS_COUNT = 20;
-
- private volatile RequestInfoMap requests;
-
- private volatile List<Pattern> storePatterns = Collections.emptyList();
+ private final RequestInfoProvider infoProvider;
@Activate
- public RequestHistoryConsolePlugin(final SlingMainServlet.Config config) {
- update(config);
- instance = this;
+ public RequestHistoryConsolePlugin(final @Reference RequestInfoProvider provider) {
+ this.infoProvider = provider;
}
-
- @Modified
- protected void update(final SlingMainServlet.Config config) {
- this.requests = (config.sling_max_record_requests() > 0)
- ? new RequestInfoMap(config.sling_max_record_requests())
- : null;
- final List<Pattern> compiledPatterns = new ArrayList<>();
- if (config.sling_store_pattern_requests() != null) {
- for (String pattern : config.sling_store_pattern_requests()) {
- if (pattern != null && pattern.trim().length() > 0) {
- compiledPatterns.add(Pattern.compile(pattern));
- }
- }
- }
- this.storePatterns = compiledPatterns;
-
- }
-
- @Deactivate
- protected void deactivate() {
- instance = null;
- clear();
- }
-
- public static void recordRequest(final SlingHttpServletRequest r) {
- final RequestHistoryConsolePlugin local = instance;
- if (local != null) {
- local.addRequest(r);
- }
- }
-
- private void addRequest(SlingHttpServletRequest r) {
- final RequestInfoMap local = requests;
- if (local != null) {
- String requestPath = r.getPathInfo();
- boolean accept = true;
- final List<Pattern> patterns = storePatterns;
- if (!patterns.isEmpty()) {
- accept = false;
- for (Pattern pattern : patterns) {
- if (pattern.matcher(requestPath).matches()) {
- accept = true;
- break;
- }
- }
- }
-
- if (accept) {
- RequestInfo info = new RequestInfo(r);
- synchronized (local) {
- local.put(info.getKey(), info);
- }
- }
- }
- }
-
- private void clear() {
- final RequestInfoMap local = requests;
- if (local != null) {
- local.clear();
- }
- }
-
- private void printLinksTable(PrintWriter pw, List<RequestInfo> values, String currentRequestIndex) {
+ private void printLinksTable(final PrintWriter pw, final List<RequestInfo> values, final String currentRequestIndex) {
final List<String> links = new ArrayList<String>();
- if (values != null) {
- for (RequestInfo info : values) {
- final String key = ResponseUtil.escapeXml(info.getKey());
- final boolean isCurrent = info.getKey().equals(currentRequestIndex);
- final StringBuilder sb = new StringBuilder();
- sb.append("<span style='white-space: pre; text-align:right; font-size:80%'>");
- sb.append(String.format("%1$8s", key));
- sb.append("</span> ");
- sb.append("<a href='" + LABEL + "?index=" + key + "'>");
- if (isCurrent) {
- sb.append("<b>");
- }
- sb.append(ResponseUtil.escapeXml(info.getLabel()));
- if (isCurrent) {
- sb.append("</b>");
- }
- sb.append("</a> ");
- links.add(sb.toString());
+ for (final RequestInfo info : values) {
+ final String key = ResponseUtil.escapeXml(info.getId());
+ final boolean isCurrent = info.getId().equals(currentRequestIndex);
+ final StringBuilder sb = new StringBuilder();
+ sb.append("<span style='white-space: pre; text-align:right; font-size:80%'>");
+ sb.append(String.format("%1$8s", key));
+ sb.append("</span> ");
+ sb.append("<a href='" + LABEL + "?index=" + key + "'>");
+ if (isCurrent) {
+ sb.append("<b>");
}
+ sb.append(ResponseUtil.escapeXml(getLabel(info)));
+ if (isCurrent) {
+ sb.append("</b>");
+ }
+ sb.append("</a> ");
+ links.add(sb.toString());
}
final int nCols = 5;
@@ -197,30 +117,21 @@
}
@Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+ protected void doGet(final HttpServletRequest req, final HttpServletResponse resp)
throws ServletException, IOException {
- final RequestInfoMap local = requests;
-
// get all requests and select request to display
final String key = req.getParameter(INDEX);
- final List<RequestInfo> values;
- RequestInfo info = null;
- if (local != null) {
- synchronized (local) {
- values = new ArrayList<>(local.values());
- if (key != null) {
- info = local.get(key);
- }
- }
- } else {
- values = null;
+ final RequestInfo info = key == null ? null : this.infoProvider.getRequestInfo(key);
+ final List<RequestInfo> values = new ArrayList<>();
+ for(final RequestInfo i : this.infoProvider.getRequestInfos()) {
+ values.add(i);
}
final PrintWriter pw = resp.getWriter();
- if (local != null) {
+ if (this.infoProvider.getMayNumberOfInfos() > 0) {
pw.println("<p class='statline ui-state-highlight'>Recorded "
- + values.size() + " requests (max: " + local.getMaxSize() + ")</p>");
+ + values.size() + " requests (max: " + this.infoProvider.getMayNumberOfInfos() + ")</p>");
} else {
pw.println("<p class='statline ui-state-highlight'>Request Recording disabled</p>");
}
@@ -243,109 +154,42 @@
pw.printf(
"<th class='ui-widget-header'>Request %s (%s %s) by %s - RequestProgressTracker Info</th>%n",
key, ResponseUtil.escapeXml(info.getMethod()),
- ResponseUtil.escapeXml(info.getPathInfo()), ResponseUtil.escapeXml(info.getUser()));
+ ResponseUtil.escapeXml(info.getPath()), ResponseUtil.escapeXml(info.getUserId()));
pw.println("</tr>");
pw.println("</thead>");
pw.println("<tbody>");
// Request Progress Tracker Info
- pw.println("<tr><td>");
- final Iterator<String> it = info.getTracker().getMessages();
- pw.print("<pre>");
- while (it.hasNext()) {
- pw.print(ResponseUtil.escapeXml(it.next()));
- }
+ pw.println("<tr><td><pre>");
+ pw.print(ResponseUtil.escapeXml(info.getLog()));
pw.println("</pre></td></tr>");
pw.println("</tbody></table>");
}
}
@Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+ protected void doPost(final HttpServletRequest req, final HttpServletResponse resp)
throws IOException {
if (req.getParameter(CLEAR) != null) {
- clear();
+ this.infoProvider.clear();
resp.sendRedirect(req.getRequestURI());
}
}
- private static class RequestInfo {
+ public String getLabel(final RequestInfo info) {
+ final StringBuilder sb = new StringBuilder();
- private static AtomicLong requestCounter = new AtomicLong(0);
+ sb.append(info.getMethod());
+ sb.append(' ');
- private final String key;
-
- private final String method;
-
- private final String pathInfo;
-
- private final String user;
-
- private final RequestProgressTracker tracker;
-
- RequestInfo(SlingHttpServletRequest request) {
- this.key = String.valueOf(requestCounter.incrementAndGet());
- this.method = request.getMethod();
- this.pathInfo = request.getPathInfo();
- this.user = request.getRemoteUser();
- this.tracker = request.getRequestProgressTracker();
+ final String path = info.getPath();
+ if (path.length() > 0) {
+ sb.append(ResourceUtil.getName(path));
+ } else {
+ sb.append('/');
}
- public String getKey() {
- return key;
- }
-
- public String getMethod() {
- return method;
- }
-
- public String getPathInfo() {
- return pathInfo;
- }
-
- public String getUser() {
- return user;
- }
-
- public String getLabel() {
- final StringBuilder sb = new StringBuilder();
-
- sb.append(getMethod());
- sb.append(' ');
-
- final String path = getPathInfo();
- if (path != null && path.length() > 0) {
- sb.append(ResourceUtil.getName(getPathInfo()));
- } else {
- sb.append('/');
- }
-
- return sb.toString();
- }
-
- public RequestProgressTracker getTracker() {
- return tracker;
- }
- }
-
- private static class RequestInfoMap extends LinkedHashMap<String, RequestInfo> {
-
- private static final long serialVersionUID = 4120391774146501524L;
-
- private int maxSize;
-
- RequestInfoMap(int maxSize) {
- this.maxSize = maxSize;
- }
-
- @Override
- protected boolean removeEldestEntry(java.util.Map.Entry<String, RequestInfo> eldest) {
- return size() > maxSize;
- }
-
- public int getMaxSize() {
- return maxSize;
- }
+ return sb.toString();
}
}
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/engine/impl/debug/RequestInfoProviderImpl.java b/src/main/java/org/apache/sling/engine/impl/debug/RequestInfoProviderImpl.java
new file mode 100644
index 0000000..8afe76f
--- /dev/null
+++ b/src/main/java/org/apache/sling/engine/impl/debug/RequestInfoProviderImpl.java
@@ -0,0 +1,209 @@
+/*
+ * 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.debug;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.ConcurrentNavigableMap;
+import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.regex.Pattern;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.engine.RequestInfo;
+import org.apache.sling.engine.RequestInfoProvider;
+import org.apache.sling.engine.impl.SlingMainServlet;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Modified;
+
+@Component(service = {RequestInfoProvider.class}, configurationPid = SlingMainServlet.PID)
+public class RequestInfoProviderImpl implements RequestInfoProvider {
+
+ /** Default for stored requests */
+ public static final int STORED_REQUESTS_COUNT = 20;
+
+ private volatile ConcurrentNavigableMap<String, RequestInfo> requests;
+
+ private volatile List<Pattern> patterns;
+
+ private volatile int maxSize;
+
+ private static volatile RequestInfoProviderImpl INSTANCE;
+
+ @Activate
+ public RequestInfoProviderImpl(final SlingMainServlet.Config config) {
+ update(config);
+ INSTANCE = this;
+ }
+
+ @Modified
+ protected void update(final SlingMainServlet.Config config) {
+ this.maxSize = config.sling_max_record_requests();
+ if ( this.maxSize < 0 ) {
+ this.maxSize = 0;
+ }
+ this.requests = (this.maxSize > 0) ? new ConcurrentSkipListMap<>() : null;
+ final List<Pattern> compiledPatterns = new ArrayList<>();
+ if (config.sling_store_pattern_requests() != null) {
+ for (final String pattern : config.sling_store_pattern_requests()) {
+ if (pattern != null && pattern.trim().length() > 0) {
+ compiledPatterns.add(Pattern.compile(pattern.trim()));
+ }
+ }
+ }
+ this.patterns = compiledPatterns;
+
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ INSTANCE = null;
+ this.requests = null;
+ this.patterns = Collections.emptyList();
+ }
+
+ public static void recordRequest(final SlingHttpServletRequest r) {
+ final RequestInfoProviderImpl local = INSTANCE;
+ if (local != null) {
+ local.addRequest(r);
+ }
+ }
+
+ private void addRequest(final SlingHttpServletRequest r) {
+ final ConcurrentNavigableMap<String, RequestInfo> local = requests;
+ if (local != null) {
+ final String requestPath = r.getPathInfo();
+ final List<Pattern> patterns = this.patterns;
+ boolean accept = patterns.isEmpty();
+ for (Pattern pattern : patterns) {
+ if (pattern.matcher(requestPath).matches()) {
+ accept = true;
+ break;
+ }
+ }
+
+ if (accept) {
+ final RequestInfo info = new RequestInfoImpl(r);
+ synchronized (local) {
+ if ( local.size() == this.maxSize ) {
+ local.remove(local.firstKey());
+ }
+ local.put(info.getId(), info);
+ }
+ }
+ }
+ }
+
+ @Override
+ public int getMayNumberOfInfos() {
+ return this.maxSize;
+ }
+
+ @Override
+ public void clear() {
+ final ConcurrentNavigableMap<String, RequestInfo> local = requests;
+ if (local != null) {
+ local.clear();
+ }
+ }
+
+ @Override
+ public RequestInfo getRequestInfo(final String id) {
+ final ConcurrentNavigableMap<String, RequestInfo> local = requests;
+ if ( local != null ) {
+ return local.get(id);
+ }
+ return null;
+ }
+
+ @Override
+ public Iterable<RequestInfo> getRequestInfos() {
+ final ConcurrentNavigableMap<String, RequestInfo> local = requests;
+ if ( local != null ) {
+ return local.values();
+ }
+ return Collections.emptyList();
+ }
+
+ private static class RequestInfoImpl implements RequestInfo {
+
+ private static AtomicLong requestCounter = new AtomicLong(0);
+
+ private final String id;
+
+ private final String method;
+
+ private final String path;
+
+ private final String userId;
+
+ private final String log;
+
+ RequestInfoImpl(final SlingHttpServletRequest request) {
+ this.id = String.valueOf(System.currentTimeMillis()).concat("-").concat(String.valueOf(requestCounter.incrementAndGet()));
+ this.method = request.getMethod();
+ this.path = request.getPathInfo() == null ? "" : request.getPathInfo();
+ this.userId = request.getRemoteUser();
+ String text;
+ try ( final StringWriter writer = new StringWriter()) {
+ final PrintWriter pw = new PrintWriter(writer);
+ request.getRequestProgressTracker().dump(pw);
+ pw.flush();
+ text = writer.toString();
+ } catch ( final IOException ioe) {
+ text = "";
+ }
+ this.log = text;
+ }
+
+ @Override
+ public @NotNull String getId() {
+ return this.id;
+ }
+
+ @Override
+ public @NotNull String getMethod() {
+ return this.method;
+ }
+
+ @Override
+ public @NotNull String getPath() {
+ return this.path;
+ }
+
+ @Override
+ public @Nullable String getUserId() {
+ return this.userId;
+ }
+
+ @Override
+ public @NotNull String getLog() {
+ return this.log;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/engine/package-info.java b/src/main/java/org/apache/sling/engine/package-info.java
index c4c2df0..7843654 100644
--- a/src/main/java/org/apache/sling/engine/package-info.java
+++ b/src/main/java/org/apache/sling/engine/package-info.java
@@ -17,6 +17,6 @@
* under the License.
*/
-@org.osgi.annotation.versioning.Version("2.4.0")
+@org.osgi.annotation.versioning.Version("2.5.0")
package org.apache.sling.engine;
diff --git a/src/test/java/org/apache/sling/engine/impl/debug/RequestInfoProviderImplTest.java b/src/test/java/org/apache/sling/engine/impl/debug/RequestInfoProviderImplTest.java
new file mode 100644
index 0000000..989c6d8
--- /dev/null
+++ b/src/test/java/org/apache/sling/engine/impl/debug/RequestInfoProviderImplTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.debug;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.request.builder.Builders;
+import org.apache.sling.engine.RequestInfo;
+import org.apache.sling.engine.impl.SlingMainServlet;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class RequestInfoProviderImplTest {
+
+ @Test public void testDisabledProvider() {
+ final SlingMainServlet.Config config = Mockito.mock(SlingMainServlet.Config.class);
+ Mockito.when(config.sling_max_record_requests()).thenReturn(0);
+
+ final SlingHttpServletRequest request = Mockito.mock(SlingHttpServletRequest.class);
+ Mockito.when(request.getPathInfo()).thenReturn("/content");
+ Mockito.when(request.getRemoteUser()).thenReturn("admin");
+ Mockito.when(request.getMethod()).thenReturn("GET");
+ Mockito.when(request.getRequestProgressTracker()).thenReturn(Builders.newRequestProgressTracker());
+
+ final RequestInfoProviderImpl provider = new RequestInfoProviderImpl(config);
+ assertEquals(0, provider.getMayNumberOfInfos());
+ RequestInfoProviderImpl.recordRequest(request);
+
+ assertFalse(provider.getRequestInfos().iterator().hasNext());
+ }
+
+ @Test public void testEnabledProvider() {
+ final SlingMainServlet.Config config = Mockito.mock(SlingMainServlet.Config.class);
+ Mockito.when(config.sling_max_record_requests()).thenReturn(5);
+
+ final SlingHttpServletRequest request = Mockito.mock(SlingHttpServletRequest.class);
+ Mockito.when(request.getPathInfo()).thenReturn("/content");
+ Mockito.when(request.getRemoteUser()).thenReturn("admin");
+ Mockito.when(request.getMethod()).thenReturn("GET");
+ Mockito.when(request.getRequestProgressTracker()).thenReturn(Builders.newRequestProgressTracker());
+
+ final RequestInfoProviderImpl provider = new RequestInfoProviderImpl(config);
+ assertEquals(5, provider.getMayNumberOfInfos());
+ RequestInfoProviderImpl.recordRequest(request);
+
+ String id = null;
+ for(final RequestInfo info : provider.getRequestInfos()) {
+ if ( id != null ) {
+ fail("More than one request info");
+ }
+ id = info.getId();
+ }
+ final RequestInfo info = provider.getRequestInfo(id);
+ assertNotNull(info);
+
+ assertEquals("/content", info.getPath());
+ assertEquals("admin", info.getUserId());
+ assertEquals(id, info.getId());
+ assertEquals("GET", info.getMethod());
+ assertFalse(info.getLog().isEmpty());
+ }
+}