From c558076a1981adabbe99c1ec3dbf869ecb27cace Mon Sep 17 00:00:00 2001 From: Jonatan Kronqvist Date: Thu, 19 Apr 2012 06:33:34 +0000 Subject: [PATCH] Implemented #8694 - API providing profiling info for TestBench 3.x svn changeset:23582/svn branch:6.8 --- .../gwt/client/ApplicationConnection.java | 32 +++- .../server/AbstractApplicationPortlet.java | 8 + .../server/AbstractApplicationServlet.java | 6 + .../server/AbstractCommunicationManager.java | 22 ++- .../terminal/gwt/server/RequestTimer.java | 138 ++++++++++++++++++ 5 files changed, 199 insertions(+), 7 deletions(-) create mode 100644 src/com/vaadin/terminal/gwt/server/RequestTimer.java diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index 7a3a28495a..93e2657eb4 100644 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -224,12 +224,22 @@ public class ApplicationConnection { return ap.@com.vaadin.terminal.gwt.client.ApplicationConnection::hasActiveRequest()() || ap.@com.vaadin.terminal.gwt.client.ApplicationConnection::isExecutingDeferredCommands()(); } + var vi = ap.@com.vaadin.terminal.gwt.client.ApplicationConnection::getVersionInfo()(); if (vi) { client.getVersionInfo = function() { return vi; } } + + client.getProfilingData = function() { + var pd = [ + ap.@com.vaadin.terminal.gwt.client.ApplicationConnection::lastProcessingTime, + ap.@com.vaadin.terminal.gwt.client.ApplicationConnection::totalProcessingTime + ]; + pd = pd.concat(ap.@com.vaadin.terminal.gwt.client.ApplicationConnection::testBenchServerStatus); + return pd; + } client.getElementByPath = function(id) { return componentLocator.@com.vaadin.terminal.gwt.client.ComponentLocator::getElementByPath(Ljava/lang/String;)(id); @@ -632,6 +642,13 @@ public class ApplicationConnection { } int cssWaits = 0; + + protected int lastProcessingTime; + + protected int totalProcessingTime; + + private ValueMap testBenchServerStatus; + static final int MAX_CSS_WAITS = 100; protected void handleWhenCSSLoaded(final String jsonText, @@ -952,6 +969,13 @@ public class ApplicationConnection { json.getValueMap("typeMappings"), widgetSet); } + /* + * Hook for TestBench to get details about server status + */ + if (json.containsKey("tbss")) { + testBenchServerStatus = json.getValueMap("tbss"); + } + Command c = new Command() { public void execute() { VConsole.dirUIDL(json, configuration); @@ -1129,10 +1153,12 @@ public class ApplicationConnection { // TODO build profiling for widget impl loading time - final long prosessingTime = (new Date().getTime()) - - start.getTime(); + lastProcessingTime = (int) ((new Date().getTime()) - start + .getTime()); + totalProcessingTime += lastProcessingTime; + VConsole.log(" Processing time was " - + String.valueOf(prosessingTime) + "ms for " + + String.valueOf(lastProcessingTime) + "ms for " + jsonText.length() + " characters of JSON"); VConsole.log("Referenced paintables: " + idToPaintableDetail.size()); diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java index acae039e8b..a5923cb47f 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java @@ -326,6 +326,11 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet protected void handleRequest(PortletRequest request, PortletResponse response) throws PortletException, IOException { + RequestTimer.RequestWrapper wrappedRequest = new RequestTimer.RequestWrapper( + request); + RequestTimer requestTimer = RequestTimer.get(wrappedRequest); + requestTimer.start(wrappedRequest); + RequestType requestType = getRequestType(request); if (requestType == RequestType.UNKNOWN) { @@ -490,6 +495,9 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet request, response); } + + requestTimer.stop(); + RequestTimer.set(wrappedRequest, requestTimer); } } } diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java index 13082cf1aa..04ea423004 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java @@ -401,6 +401,10 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + RequestTimer.RequestWrapper wrappedRequest = new RequestTimer.RequestWrapper( + request); + RequestTimer requestTimer = RequestTimer.get(wrappedRequest); + requestTimer.start(wrappedRequest); RequestType requestType = getRequestType(request); if (!ensureCookiesEnabled(requestType, request, response)) { @@ -549,6 +553,8 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements request, response); } + requestTimer.stop(); + RequestTimer.set(wrappedRequest, requestTimer); } } diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java index c0654359a1..9a6bccebb8 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java @@ -912,7 +912,7 @@ public abstract class AbstractCommunicationManager implements repaintAll = true; } - writeUidlResponce(callback, repaintAll, outWriter, window, + writeUidlResponse(request, callback, repaintAll, outWriter, window, analyzeLayouts); } @@ -922,9 +922,9 @@ public abstract class AbstractCommunicationManager implements } - public void writeUidlResponce(Callback callback, boolean repaintAll, - final PrintWriter outWriter, Window window, boolean analyzeLayouts) - throws PaintException { + public void writeUidlResponse(Request request, Callback callback, + boolean repaintAll, final PrintWriter outWriter, Window window, + boolean analyzeLayouts) throws PaintException { outWriter.print("\"changes\":["); ArrayList paintables = null; @@ -1205,6 +1205,20 @@ public abstract class AbstractCommunicationManager implements if (dragAndDropService != null) { dragAndDropService.printJSONResponse(outWriter); } + + writePerformanceDataForTestBench(request, outWriter); + } + + /** + * Adds the performance timing data used by TestBench 3 to the UIDL + * response. + */ + private void writePerformanceDataForTestBench(final Request request, + final PrintWriter outWriter) { + Long totalTime = (Long) request.getAttribute("TOTAL"); + Long lastRequestTime = (Long) request.getAttribute("LASTREQUEST"); + outWriter.write(String.format(", \"tbss\":[%d, %d]", totalTime, + lastRequestTime)); } private int getTimeoutInterval() { diff --git a/src/com/vaadin/terminal/gwt/server/RequestTimer.java b/src/com/vaadin/terminal/gwt/server/RequestTimer.java new file mode 100644 index 0000000000..3649ed3a80 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/server/RequestTimer.java @@ -0,0 +1,138 @@ +package com.vaadin.terminal.gwt.server; + +import javax.portlet.PortletRequest; +import javax.portlet.PortletSession; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +/** + * Times the handling of requests and stores the information as an attribute in + * the request. The timing info is later passed on to the client in the UIDL and + * the client provides JavaScript API for accessing this data from e.g. + * TestBench. + * + * @author Jonatan Kronqvist / Vaadin Ltd + */ +public class RequestTimer { + public static final String SESSION_ATTR_ID = "REQUESTTIMER"; + + private long requestStartTime = 0; + private long totalSessionTime = 0; + private long lastRequestTime = -1; + + /** + * This class acts as a proxy for setting and getting session and request + * attributes on HttpServletRequests and PortletRequests. Using this class + * we don't need to duplicate code everywhere. + */ + static class RequestWrapper { + private final HttpServletRequest servletRequest; + private final PortletRequest portletRequest; + + public RequestWrapper(HttpServletRequest servletRequest) { + this.servletRequest = servletRequest; + portletRequest = null; + } + + public RequestWrapper(PortletRequest portletRequest) { + this.portletRequest = portletRequest; + servletRequest = null; + } + + public void setAttribute(String name, Object value) { + if (servletRequest != null) { + servletRequest.setAttribute(name, value); + } else { + portletRequest.setAttribute(name, value); + } + } + + public void setSessionAttribute(String name, Object value) { + if (servletRequest != null) { + HttpSession session = servletRequest.getSession(); + if (session != null) { + session.setAttribute(name, value); + } + } else { + PortletSession portletSession = portletRequest + .getPortletSession(); + if (portletSession != null) { + portletSession.setAttribute(name, value); + } + } + } + + public Object getSessionAttribute(String name) { + if (servletRequest != null) { + HttpSession session = servletRequest.getSession(); + if (session != null) { + return session.getAttribute(name); + } + } else { + PortletSession portletSession = portletRequest + .getPortletSession(); + if (portletSession != null) { + return portletSession.getAttribute(name); + } + } + return null; + } + } + + /** + * Starts the timing of a request. This should be called before any + * processing of the request. + * + * @param request + * the request. + */ + public void start(RequestWrapper request) { + requestStartTime = System.nanoTime(); + request.setAttribute("TOTAL", totalSessionTime); + request.setAttribute("LASTREQUEST", lastRequestTime); + } + + /** + * Stops the timing of a request. This should be called when all processing + * of a request has finished. + */ + public void stop() { + // Measure and store the total handling time. This data can be + // used in TestBench 3 tests. + long time = (System.nanoTime() - requestStartTime) / 1000000; + lastRequestTime = time; + totalSessionTime += time; + } + + /** + * Returns a valid request timer for the specified request. Timers are + * session bound. + * + * @param request + * the request for which to get a valid timer. + * @return a valid timer. + */ + public static RequestTimer get(RequestWrapper request) { + RequestTimer timer = (RequestTimer) request + .getSessionAttribute(SESSION_ATTR_ID); + if (timer == null) { + timer = new RequestTimer(); + } + return timer; + } + + /** + * Associates the specified request timer with the specified request. Since + * {@link #get(RequestWrapper)} will, at one point or another, return a new + * instance, this method should be called to keep the request <-> timer + * association updated. + * + * @param request + * the request for which to set the timer. + * @param requestTimer + * the timer. + */ + public static void set(RequestWrapper request, RequestTimer requestTimer) { + request.setSessionAttribute(RequestTimer.SESSION_ATTR_ID, requestTimer); + } +} -- 2.39.5