Author: fmeschbe
Date: Mon Nov 22 14:42:22 2010
New Revision: 1037739
URL: http://svn.apache.org/viewvc?rev=1037739&view=rev
Log:
SLING-1872 Rewamp the recent requests display:
- Adapt to new JQuery UI styles
- Use POST requests to clear recordings
- Add configuration option to SlingMainServlet for max number of recorded
requests
- Replace rotated array by LinkedHashMap to keep requests
- Copy displayed values instead of keep the SlingHttpServletRequest for
display
Removed:
sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/EngineBundleActivator.java
Modified:
sling/trunk/bundles/engine/pom.xml
sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/SlingHttpServletRequestImpl.java
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/request/RequestHistoryConsolePlugin.java
sling/trunk/bundles/engine/src/main/resources/OSGI-INF/metatype/metatype.properties
Modified: sling/trunk/bundles/engine/pom.xml
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/engine/pom.xml?rev=1037739&r1=1037738&r2=1037739&view=diff
==============================================================================
--- sling/trunk/bundles/engine/pom.xml (original)
+++ sling/trunk/bundles/engine/pom.xml Mon Nov 22 14:42:22 2010
@@ -72,9 +72,6 @@
javax.portlet;resolution:=optional,
*
</Import-Package>
- <Bundle-Activator>
- org.apache.sling.engine.impl.EngineBundleActivator
- </Bundle-Activator>
<Embed-Dependency>
commons-fileupload
</Embed-Dependency>
Modified:
sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/SlingHttpServletRequestImpl.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/SlingHttpServletRequestImpl.java?rev=1037739&r1=1037738&r2=1037739&view=diff
==============================================================================
---
sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/SlingHttpServletRequestImpl.java
(original)
+++
sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/SlingHttpServletRequestImpl.java
Mon Nov 22 14:42:22 2010
@@ -48,7 +48,6 @@ import org.apache.sling.api.resource.Res
import org.apache.sling.engine.impl.helper.NullResourceBundle;
import org.apache.sling.engine.impl.parameters.ParameterSupport;
import org.apache.sling.engine.impl.request.RequestData;
-import org.apache.sling.engine.impl.request.RequestHistoryConsolePlugin;
import org.apache.sling.engine.impl.request.SlingRequestDispatcher;
import org.osgi.service.http.HttpContext;
import org.osgi.service.useradmin.Authorization;
@@ -74,7 +73,6 @@ public class SlingHttpServletRequestImpl
pathInfo = pathInfo.concat(servletRequest.getPathInfo());
}
this.pathInfo = pathInfo;
- RequestHistoryConsolePlugin.recordRequest(this);
}
/**
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=1037739&r1=1037738&r2=1037739&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
Mon Nov 22 14:42:22 2010
@@ -54,6 +54,7 @@ import org.apache.sling.engine.impl.help
import org.apache.sling.engine.impl.helper.SlingServletContext;
import org.apache.sling.engine.impl.log.RequestLogger;
import org.apache.sling.engine.impl.request.RequestData;
+import org.apache.sling.engine.impl.request.RequestHistoryConsolePlugin;
import org.apache.sling.engine.servlets.ErrorHandler;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
@@ -67,7 +68,7 @@ import org.slf4j.LoggerFactory;
* The <code>SlingMainServlet</code> TODO
*/
@SuppressWarnings("serial")
-...@component(immediate = true, label = "%sling.name", description =
"%sling.description")
+...@component(immediate = true, metatype = true, label = "%sling.name",
description = "%sling.description")
@Properties( {
@Property(name = Constants.SERVICE_VENDOR, value = "The Apache Software
Foundation"),
@Property(name = Constants.SERVICE_DESCRIPTION, value = "Sling Servlet")
@@ -92,6 +93,9 @@ public class SlingMainServlet extends Ge
@Property(boolValue=DEFAULT_ALLOW_TRACE)
public static final String PROP_ALLOW_TRACE = "sling.trace.allow";
+ @Property(intValue = RequestHistoryConsolePlugin.STORED_REQUESTS_COUNT)
+ private static final String PROP_MAX_RECORD_REQUESTS =
"sling.max.record.requests";
+
@Reference
private HttpService httpService;
@@ -312,6 +316,17 @@ public class SlingMainServlet extends Ge
// Setup configuration printer
this.printerRegistration =
WebConsoleConfigPrinter.register(bundleContext, filterManager);
+ // setup the request info recorder
+ try {
+ int maxRequests = OsgiUtil.toInteger(
+ componentConfig.get(PROP_MAX_RECORD_REQUESTS),
+ RequestHistoryConsolePlugin.STORED_REQUESTS_COUNT);
+ RequestHistoryConsolePlugin.initPlugin(bundleContext, maxRequests);
+ } catch (Throwable t) {
+ log.debug(
+ "Unable to register web console request recorder plugin.", t);
+ }
+
// provide the SlingRequestProcessor service
Hashtable<String, String> srpProps = new Hashtable<String, String>();
srpProps.put(Constants.SERVICE_VENDOR, "The Apache Software
Foundation");
@@ -328,6 +343,14 @@ public class SlingMainServlet extends Ge
requestProcessorRegistration = null;
}
+ // unregister request recorder plugin
+ try {
+ RequestHistoryConsolePlugin.destroyPlugin();
+ } catch (Throwable t) {
+ log.debug(
+ "Problem unregistering web console request recorder plugin.",
t);
+ }
+
// this reverses the activation setup
if ( this.printerRegistration != null ) {
WebConsoleConfigPrinter.unregister(this.printerRegistration);
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=1037739&r1=1037738&r2=1037739&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
Mon Nov 22 14:42:22 2010
@@ -56,6 +56,7 @@ import org.apache.sling.engine.impl.filt
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;
import org.apache.sling.engine.servlets.ErrorHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -131,6 +132,9 @@ public class SlingRequestProcessorImpl i
final SlingHttpServletRequest request = requestData.getSlingRequest();
final SlingHttpServletResponse response =
requestData.getSlingResponse();
+ // record the request for the web console display
+ RequestHistoryConsolePlugin.recordRequest(request);
+
// request entry log
if (requestLogger != null) {
requestLogger.logRequestEntry(request, response);
Modified:
sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/request/RequestHistoryConsolePlugin.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/request/RequestHistoryConsolePlugin.java?rev=1037739&r1=1037738&r2=1037739&view=diff
==============================================================================
---
sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/request/RequestHistoryConsolePlugin.java
(original)
+++
sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/request/RequestHistoryConsolePlugin.java
Mon Nov 22 14:42:22 2010
@@ -24,7 +24,9 @@ import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
@@ -32,6 +34,8 @@ import javax.servlet.http.HttpServletReq
import javax.servlet.http.HttpServletResponse;
import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.request.RequestProgressTracker;
+import org.apache.sling.api.resource.ResourceUtil;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceRegistration;
@@ -45,7 +49,9 @@ import org.osgi.framework.ServiceRegistr
public class RequestHistoryConsolePlugin {
public static final String LABEL = "requests";
+
public static final String INDEX = "index";
+
public static final String CLEAR = "clear";
private static Plugin instance;
@@ -63,19 +69,20 @@ public class RequestHistoryConsolePlugin
}
}
- public static void initPlugin(BundleContext context) {
+ public static void initPlugin(BundleContext context, int maxRequests) {
if (instance == null) {
- Plugin tmp = new Plugin();
+ Plugin tmp = new Plugin(maxRequests);
final Dictionary<String, Object> props = new Hashtable<String,
Object>();
props.put(Constants.SERVICE_DESCRIPTION,
"Web Console Plugin to display information about recent Sling
requests");
- props.put(Constants.SERVICE_VENDOR, "The Apache Software
Foundation");
+ props.put(Constants.SERVICE_VENDOR,
+ "The Apache Software Foundation");
props.put(Constants.SERVICE_PID, tmp.getClass().getName());
props.put("felix.webconsole.label", LABEL);
props.put("felix.webconsole.title", "Recent requests");
serviceRegistration = context.registerService(
- "javax.servlet.Servlet", tmp, props);
+ "javax.servlet.Servlet", tmp, props);
instance = tmp;
}
}
@@ -95,72 +102,83 @@ public class RequestHistoryConsolePlugin
public static final class Plugin extends HttpServlet {
- private final SlingHttpServletRequest[] requests = new
SlingHttpServletRequest[STORED_REQUESTS_COUNT];
+ private final RequestInfoMap requests;
- /** Need to store methods separately, apparently requests clear this
data when done processing */
- private final String [] methods = new String[STORED_REQUESTS_COUNT];
-
- private int lastRequestIndex = -1;
+ Plugin(int maxRequests) {
+ requests = (maxRequests > 0)
+ ? new RequestInfoMap(maxRequests)
+ : null;
+ }
- private synchronized void addRequest(SlingHttpServletRequest r) {
- int index = lastRequestIndex + 1;
- if (index >= requests.length) {
- index = 0;
+ public void deactivate() {
+ if (serviceRegistration != null) {
+ serviceRegistration.unregister();
+ serviceRegistration = null;
}
- requests[index] = r;
- methods[index] = r.getMethod();
- lastRequestIndex = index;
+
+ clear();
}
- private synchronized void clear() {
- for(int i=0; i < requests.length; i++) {
- requests[i] = null;
+ private void addRequest(SlingHttpServletRequest r) {
+ if (requests != null) {
+ synchronized (requests) {
+ RequestInfo info = new RequestInfo(r);
+ requests.put(info.getKey(), info);
+ }
}
- lastRequestIndex = -1;
}
- private int getArrayIndex(int displayIndex) {
- int result = lastRequestIndex - displayIndex;
- if (result < 0) {
- result += requests.length;
+ private void clear() {
+ if (requests != null) {
+ synchronized (requests) {
+ requests.clear();
+ }
}
- return result;
}
- private String getLinksTable(int currentRequestIndex) {
+ private String getLinksTable(String currentRequestIndex) {
final List<String> links = new ArrayList<String>();
- for (int i = 0; i < requests.length; i++) {
- final StringBuilder sb = new StringBuilder();
- if (requests[i] != null) {
- sb.append("<a href='" + LABEL + "?index=" + i + "'>");
- if (i == currentRequestIndex) {
- sb.append("<b>");
- }
- sb.append(getRequestLabel(getArrayIndex(i)));
- if (i == currentRequestIndex) {
- sb.append("</b>");
+ if (requests != null) {
+ synchronized (requests) {
+ for (RequestInfo info : requests.values()) {
+ final boolean isCurrent = info.getKey().equals(
+ currentRequestIndex);
+ final StringBuilder sb = new StringBuilder();
+ sb.append("<a href='" + LABEL + "?index="
+ + info.getKey() + "'>");
+ if (isCurrent) {
+ sb.append("<b>");
+ }
+ sb.append(info.getLabel());
+ if (isCurrent) {
+ sb.append("</b>");
+ }
+ sb.append("</a> ");
+ links.add(sb.toString());
}
- sb.append("</a> ");
- links.add(sb.toString());
}
}
final int nCols = 5;
- while((links.size() % nCols) != 0) {
+ while ((links.size() % nCols) != 0) {
links.add(" ");
}
final StringBuilder tbl = new StringBuilder();
- tbl.append("<table>\n<tr>\n");
- int i=0;
- for(String str : links) {
- if( (i++ % nCols) == 0) {
- tbl.append("</tr>\n<tr>\n");
- }
- tbl.append("<td>");
- tbl.append(str);
- tbl.append("</td>\n");
+ tbl.append("<table class='nicetable ui-widget'>\n<tr>\n");
+ if (links.isEmpty()) {
+ tbl.append("No Requests recorded");
+ } else {
+ int i = 0;
+ for (String str : links) {
+ if ((i++ % nCols) == 0) {
+ tbl.append("</tr>\n<tr>\n");
+ }
+ tbl.append("<td>");
+ tbl.append(str);
+ tbl.append("</td>\n");
+ }
}
tbl.append("</tr>\n");
@@ -171,72 +189,75 @@ public class RequestHistoryConsolePlugin
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
- // If so requested, clear our data
- if(req.getParameter(CLEAR) != null) {
- clear();
- resp.sendRedirect(LABEL);
- return;
- }
// Select request to display
- int index = 0;
- final String tmp = req.getParameter(INDEX);
- if (tmp != null) {
- try {
- index = Integer.parseInt(tmp);
- } catch (NumberFormatException ignore) {
- // ignore
+ RequestInfo info = null;
+ String key = req.getParameter(INDEX);
+ if (key != null && requests != null) {
+ synchronized (requests) {
+ info = requests.get(key);
}
}
- // index is relative to lastRequestIndex
- final int arrayIndex = getArrayIndex(index);
+ final PrintWriter pw = resp.getWriter();
- SlingHttpServletRequest r = null;
- try {
- r = requests[arrayIndex];
- } catch (ArrayIndexOutOfBoundsException ignore) {
- // ignore
+ if (requests != null) {
+ pw.println("<p class='statline ui-state-highlight'>Recorded "
+ + requests.size() + " requests (max: "
+ + requests.getMaxSize() + ")</p>");
+ } else {
+ pw.println("<p class='statline ui-state-highlight'>Request
Recording disabled</p>");
}
- final PrintWriter pw = resp.getWriter();
+ pw.println("<div class='ui-widget-header ui-corner-top
buttonGroup'>");
+ pw.println("<span style='float: left; margin-left: 1em'>Recent
Requests</span>");
+ pw.println("<form method='POST'><input type='hidden' name='clear'
value='clear'><input type='submit' value='Clear' class='ui-state-default
ui-corner-all'></form>");
+ pw.println("</div>");
+
+ pw.println(getLinksTable(key));
+ pw.println("<br/>");
+
+ if (info != null) {
- pw.println("<table class='content' cellpadding='0' cellspacing='0'
width='100%'>");
+ pw.println("<table class='nicetable ui-widget'>");
- // Links to other requests
- pw.println("<thead>");
- pw.println("<tr class='content'>");
- pw.println("<th colspan='2'class='content container'>Recent
Requests");
- pw.println(" (<a href='" + LABEL + "?clear=clear'>Clear</a>)");
- pw.println("</th>");
- pw.println("</thead>");
- pw.println("<tbody>");
- pw.println("<tr class='content'><td>");
- pw.println(getLinksTable(index));
- pw.println("</td></tr>");
+ // Links to other requests
+ pw.println("<thead>");
+ pw.println("<tr>");
+ pw.printf(
+ "<th class='ui-widget-header'>Request %s (%s %s) by %s -
RequestProgressTracker Info</th>%n",
+ key, info.getMethod(), info.getPathInfo(), info.getUser());
+ pw.println("</tr>");
+ pw.println("</thead>");
+
+ pw.println("<tbody>");
- if (r != null) {
// Request Progress Tracker Info
- pw.println("<tr class='content'>");
- pw.println("<th colspan='2'class='content container'>");
- pw.print("Request " + index + " (" + getRequestLabel(index) +
") - RequestProgressTracker Info");
- pw.println("</th></tr>");
- pw.println("<tr><td colspan='2'>");
- final Iterator<String> it =
r.getRequestProgressTracker().getMessages();
+ pw.println("<tr><td>");
+ final Iterator<String> it = info.getTracker().getMessages();
pw.print("<pre>");
while (it.hasNext()) {
pw.print(escape(it.next()));
}
pw.println("</pre></td></tr>");
+ pw.println("</tbody></table>");
+ }
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+ throws IOException {
+ if (req.getParameter(CLEAR) != null) {
+ clear();
+ resp.sendRedirect(req.getRequestURI());
}
- pw.println("</tbody></table>");
}
private static String escape(String str) {
final StringBuilder sb = new StringBuilder();
- for(int i=0; i < str.length(); i++) {
+ for (int i = 0; i < str.length(); i++) {
final char c = str.charAt(i);
- if(c == '<') {
+ if (c == '<') {
sb.append("<");
} else if (c == '>') {
sb.append(">");
@@ -249,23 +270,84 @@ public class RequestHistoryConsolePlugin
return sb.toString();
}
- private String getRequestLabel(int index) {
+ }
+
+ private static class RequestInfo {
+
+ private static AtomicLong requestCounter = new AtomicLong(0);
+
+ 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();
+ }
+
+ 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();
- String path = requests[index].getPathInfo();
- if (path == null) {
- path = "";
- }
- sb.append(methods[index]);
+ sb.append(getMethod());
sb.append(' ');
- final int pos = requests[index].getPathInfo().lastIndexOf('/');
- if(pos < 0) {
- sb.append(requests[index].getPathInfo());
+ final String path = getPathInfo();
+ if (path != null && path.length() > 0) {
+ sb.append(ResourceUtil.getName(getPathInfo()));
} else {
- sb.append(requests[index].getPathInfo().substring(pos+1));
+ sb.append('/');
}
+
return sb.toString();
}
+
+ public RequestProgressTracker getTracker() {
+ return tracker;
+ }
+ }
+
+ private static class RequestInfoMap extends
+ LinkedHashMap<String, RequestInfo> {
+
+ 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;
+ }
}
}
\ No newline at end of file
Modified:
sling/trunk/bundles/engine/src/main/resources/OSGI-INF/metatype/metatype.properties
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/main/resources/OSGI-INF/metatype/metatype.properties?rev=1037739&r1=1037738&r2=1037739&view=diff
==============================================================================
---
sling/trunk/bundles/engine/src/main/resources/OSGI-INF/metatype/metatype.properties
(original)
+++
sling/trunk/bundles/engine/src/main/resources/OSGI-INF/metatype/metatype.properties
Mon Nov 22 14:42:22 2010
@@ -45,6 +45,11 @@ sling.trace.allow.name = Allow the HTTP
sling.trace.allow.description = If set to true, the HTTP TRACE method will be \
enabled. By default the HTTP TRACE methods is disabled as it can be used in \
Cross Site Scripting attacks on HTTP servers.
+sling.max.record.requests.name = Number of Requests to Record
+sling.max.record.requests.description = Defines the number of requests that \
+ 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.
#
# Request Loggger Filter