This is an automated email from the ASF dual-hosted git repository.

olli pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-hc-core.git


The following commit(s) were added to refs/heads/master by this push:
     new 5d553ec  fix line endings
5d553ec is described below

commit 5d553ecf514c520f3027a4f591bac4cc5a9eb9d1
Author: Oliver Lietz <o...@apache.org>
AuthorDate: Fri Feb 2 23:58:16 2018 +0100

    fix line endings
---
 .../impl/servlet/HealthCheckExecutorServlet.java   | 808 ++++++++++-----------
 .../hc/core/impl/servlet/ResultHtmlSerializer.java | 314 ++++----
 .../hc/core/impl/servlet/ResultJsonSerializer.java | 238 +++---
 .../hc/core/impl/servlet/ResultTxtSerializer.java  |  64 +-
 .../impl/servlet/ResultTxtVerboseSerializer.java   | 274 +++----
 5 files changed, 849 insertions(+), 849 deletions(-)

diff --git 
a/src/main/java/org/apache/sling/hc/core/impl/servlet/HealthCheckExecutorServlet.java
 
b/src/main/java/org/apache/sling/hc/core/impl/servlet/HealthCheckExecutorServlet.java
index fa29500..422702c 100644
--- 
a/src/main/java/org/apache/sling/hc/core/impl/servlet/HealthCheckExecutorServlet.java
+++ 
b/src/main/java/org/apache/sling/hc/core/impl/servlet/HealthCheckExecutorServlet.java
@@ -1,404 +1,404 @@
-/*
- * 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 SF 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.hc.core.impl.servlet;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.lang3.StringEscapeUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.sling.commons.osgi.PropertiesUtil;
-import org.apache.sling.hc.api.Result;
-import org.apache.sling.hc.api.Result.Status;
-import org.apache.sling.hc.api.execution.HealthCheckExecutionOptions;
-import org.apache.sling.hc.api.execution.HealthCheckExecutionResult;
-import org.apache.sling.hc.api.execution.HealthCheckExecutor;
-import org.apache.sling.hc.api.execution.HealthCheckSelector;
-import org.osgi.service.component.ComponentContext;
-import org.osgi.service.component.annotations.Activate;
-import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.ConfigurationPolicy;
-import org.osgi.service.component.annotations.Deactivate;
-import org.osgi.service.component.annotations.Reference;
-import org.osgi.service.http.HttpService;
-import org.osgi.service.metatype.annotations.Designate;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/** Servlet that triggers the health check executor to return results via http.
- *
- * Parameters:
- * <ul>
- * <li>tags: The health check tags to take into account
- * <li>format: html|json|jsonp
- * <li>includeDebug: If true, debug messages from result log are included.
- * <li>callback: For jsonp, the JS callback function name (defaults to 
"processHealthCheckResults")
- * <li>httpStatus: health check status to http status mapping in format 
httpStatus=WARN:418,CRITICAL:503,HEALTH_CHECK_ERROR:500.
- * </ul>
- *
- * For omitted health check status values the next best code will be used 
(e.g. for httpStatus=CRITICAL:503 a result WARN will
- * return 200, CRITICAL 503 and HEALTH_CHECK_ERROR also 503). By default all 
requests answer with an http status of 200.
- * <p>
- * Useful in combination with load balancers.
- * <p>
- * NOTE: This servlet registers directly (low-level) at the HttpService and is 
not processed by sling (better performance, fewer dependencies, no 
authentication required, 503 can be sent without the progress tracker 
information). */
-@Component(
-    configurationPolicy = ConfigurationPolicy.REQUIRE
-)
-@Designate(
-    ocd = HealthCheckExecutorServletConfiguration.class
-)
-public class HealthCheckExecutorServlet extends HttpServlet {
-    private static final long serialVersionUID = 8013511523994541848L;
-
-    private static final Logger LOG = 
LoggerFactory.getLogger(HealthCheckExecutorServlet.class);
-    public static final String PARAM_SPLIT_REGEX = "[,;]+";
-
-    static class Param {
-        final String name;
-        final String description;
-        Param(String n, String d) {
-            name = n;
-            description = d;
-        }
-    }
-
-    static final Param PARAM_TAGS = new Param("tags",
-            "Comma-separated list of health checks tags to select - can also 
be specified via path, e.g. /system/health/tag1,tag2.json. Exclusions can be 
done by prepending '-' to the tag name");
-    static final Param PARAM_FORMAT = new Param("format", "Output format, 
html|json|jsonp|txt - an extension in the URL overrides this");
-    static final Param PARAM_HTTP_STATUS = new Param("httpStatus", "Specify 
HTTP result code, for example"
-            + " CRITICAL:503 (status 503 if result >= CRITICAL)"
-            + " or CRITICAL:503,HEALTH_CHECK_ERROR:500,OK:418 for more 
specific HTTP status");
-
-    static final Param PARAM_COMBINE_TAGS_WITH_OR = new 
Param("combineTagsWithOr", "Combine tags with OR, active by default. Set to 
false to combine with AND");
-    static final Param PARAM_FORCE_INSTANT_EXECUTION = new 
Param("forceInstantExecution",
-            "If true, forces instant execution by executing async health 
checks directly, circumventing the cache (2sec by default) of the 
HealthCheckExecutor");
-    static final Param PARAM_OVERRIDE_GLOBAL_TIMEOUT = new Param("timeout",
-            "(msec) a timeout status is returned for any health check still 
running after this period. Overrides the default HealthCheckExecutor timeout");
-
-    static final Param PARAM_INCLUDE_DEBUG = new Param("hcDebug", "Include the 
DEBUG output of the Health Checks");
-
-    static final Param PARAM_NAMES = new Param("names", "Comma-separated list 
of health check names to select. Exclusions can be done by prepending '-' to 
the health check name");
-
-    static final String JSONP_CALLBACK_DEFAULT = "processHealthCheckResults";
-    static final Param PARAM_JSONP_CALLBACK = new Param("callback", "name of 
the JSONP callback function to use, defaults to " + JSONP_CALLBACK_DEFAULT);
-
-    static final Param [] PARAM_LIST = { PARAM_TAGS, PARAM_NAMES, 
PARAM_FORMAT, PARAM_HTTP_STATUS, PARAM_COMBINE_TAGS_WITH_OR,
-        PARAM_FORCE_INSTANT_EXECUTION, PARAM_OVERRIDE_GLOBAL_TIMEOUT, 
PARAM_INCLUDE_DEBUG, PARAM_JSONP_CALLBACK};
-
-    static final String FORMAT_HTML = "html";
-    static final String FORMAT_JSON = "json";
-    static final String FORMAT_JSONP = "jsonp";
-    static final String FORMAT_TXT = "txt";
-    static final String FORMAT_VERBOSE_TXT = "verbose.txt";
-
-    private static final String CONTENT_TYPE_HTML = "text/html";
-    private static final String CONTENT_TYPE_TXT = "text/plain";
-    private static final String CONTENT_TYPE_JSON = "application/json";
-    private static final String CONTENT_TYPE_JSONP = "application/javascript";
-    private static final String STATUS_HEADER_NAME = "X-Health";
-
-    private static final String CACHE_CONTROL_KEY = "Cache-control";
-    private static final String CACHE_CONTROL_VALUE = "no-cache";
-
-    private String[] servletPaths;
-
-    private boolean disabled;
-
-    private String servletPath;
-
-    private String corsAccessControlAllowOrigin;
-
-    private static final String CORS_ORIGIN_HEADER_NAME = 
"Access-Control-Allow-Origin";
-
-
-    @Reference
-    private HttpService httpService;
-
-    @Reference
-    HealthCheckExecutor healthCheckExecutor;
-
-    @Reference
-    ResultHtmlSerializer htmlSerializer;
-
-    @Reference
-    ResultJsonSerializer jsonSerializer;
-
-    @Reference
-    ResultTxtSerializer txtSerializer;
-
-    @Reference
-    ResultTxtVerboseSerializer verboseTxtSerializer;
-
-    @Activate
-    protected final void activate(final 
HealthCheckExecutorServletConfiguration configuration) {
-        this.servletPath = configuration.servletPath();
-        this.disabled = configuration.disabled();
-        this.corsAccessControlAllowOrigin = 
configuration.cors_accessControlAllowOrigin();
-
-        Map<String, HttpServlet> servletsToRegister = new 
LinkedHashMap<String, HttpServlet>();
-        servletsToRegister.put(this.servletPath, this);
-        servletsToRegister.put(this.servletPath + "." + FORMAT_HTML, new 
ProxyServlet(FORMAT_HTML));
-        servletsToRegister.put(this.servletPath + "." + FORMAT_JSON, new 
ProxyServlet(FORMAT_JSON));
-        servletsToRegister.put(this.servletPath + "." + FORMAT_JSONP, new 
ProxyServlet(FORMAT_JSONP));
-        servletsToRegister.put(this.servletPath + "." + FORMAT_TXT, new 
ProxyServlet(FORMAT_TXT));
-        servletsToRegister.put(this.servletPath + "." + FORMAT_VERBOSE_TXT, 
new ProxyServlet(FORMAT_VERBOSE_TXT));
-
-        if (disabled) {
-            LOG.info("Health Check Servlet is disabled by configuration");
-            return;
-        }
-
-        for (final Map.Entry<String, HttpServlet> servlet : 
servletsToRegister.entrySet()) {
-            try {
-                LOG.debug("Registering {} to path {}", 
getClass().getSimpleName(), servlet.getKey());
-                this.httpService.registerServlet(servlet.getKey(), 
servlet.getValue(), null, null);
-            } catch (Exception e) {
-                LOG.error("Could not register health check servlet: " + e, e);
-            }
-        }
-        this.servletPaths = servletsToRegister.keySet().toArray(new String[0]);
-
-    }
-
-    @Deactivate
-    public void deactivate(final ComponentContext componentContext) {
-        if (disabled || this.servletPaths == null) {
-            return;
-        }
-
-        for (final String servletPath : this.servletPaths) {
-            try {
-                LOG.debug("Unregistering path {}", servletPath);
-                this.httpService.unregister(servletPath);
-            } catch (Exception e) {
-                LOG.error("Could not unregister health check servlet: " + e, 
e);
-            }
-        }
-        this.servletPaths = null;
-    }
-
-    protected void doGet(final HttpServletRequest request, final 
HttpServletResponse response, final String format) throws ServletException, 
IOException {
-        HealthCheckSelector selector = HealthCheckSelector.empty();
-        String pathInfo = request.getPathInfo();
-        String pathTokensStr = 
StringUtils.removeStart(splitFormat(pathInfo)[0], "/");
-
-        List<String> tags = new ArrayList<String>();
-        List<String> names = new ArrayList<String>();
-
-        if (StringUtils.isNotBlank(pathTokensStr)) {
-            String[] pathTokens = pathTokensStr.split(PARAM_SPLIT_REGEX);
-            for (String pathToken : pathTokens) {
-                if (pathToken.indexOf(' ') >= 0) {
-                    // token contains space. assume it is a name
-                    names.add(pathToken);
-                } else {
-                    tags.add(pathToken);
-                }
-            }
-        }
-        if (tags.size() == 0) {
-            // if not provided via path use parameter or default
-            tags = 
Arrays.asList(StringUtils.defaultIfEmpty(request.getParameter(PARAM_TAGS.name), 
"").split(PARAM_SPLIT_REGEX));
-        }
-        selector.withTags(tags.toArray(new String[0]));
-
-        if (names.size() == 0) {
-            // if not provided via path use parameter or default
-            names = 
Arrays.asList(StringUtils.defaultIfEmpty(request.getParameter(PARAM_NAMES.name),
 "").split(PARAM_SPLIT_REGEX));
-        }
-        selector.withNames(names.toArray(new String[0]));
-
-        final Boolean includeDebug = 
Boolean.valueOf(request.getParameter(PARAM_INCLUDE_DEBUG.name));
-        final Map<Result.Status, Integer> statusMapping = 
request.getParameter(PARAM_HTTP_STATUS.name) != null ? getStatusMapping(request
-                .getParameter(PARAM_HTTP_STATUS.name)) : null;
-
-        HealthCheckExecutionOptions executionOptions = new 
HealthCheckExecutionOptions();
-        
executionOptions.setCombineTagsWithOr(Boolean.valueOf(StringUtils.defaultString(request.getParameter(PARAM_COMBINE_TAGS_WITH_OR.name),
 "true")));
-        
executionOptions.setForceInstantExecution(Boolean.valueOf(request.getParameter(PARAM_FORCE_INSTANT_EXECUTION.name)));
-        String overrideGlobalTimeoutVal = 
request.getParameter(PARAM_OVERRIDE_GLOBAL_TIMEOUT.name);
-        if (StringUtils.isNumeric(overrideGlobalTimeoutVal)) {
-            
executionOptions.setOverrideGlobalTimeout(Integer.valueOf(overrideGlobalTimeoutVal));
-        }
-
-        List<HealthCheckExecutionResult> executionResults = 
this.healthCheckExecutor.execute(selector, executionOptions);
-
-        Result.Status mostSevereStatus = Result.Status.DEBUG;
-        for (HealthCheckExecutionResult executionResult : executionResults) {
-            Status status = executionResult.getHealthCheckResult().getStatus();
-            if (status.ordinal() > mostSevereStatus.ordinal()) {
-                mostSevereStatus = status;
-            }
-        }
-        Result overallResult = new Result(mostSevereStatus, "Overall status " 
+ mostSevereStatus);
-
-        sendNoCacheHeaders(response);
-        sendCorsHeaders(response);
-
-        if (statusMapping != null) {
-            Integer httpStatus = statusMapping.get(overallResult.getStatus());
-            response.setStatus(httpStatus);
-        }
-
-        if (FORMAT_HTML.equals(format)) {
-            sendHtmlResponse(overallResult, executionResults, request, 
response, includeDebug);
-        } else if (FORMAT_JSON.equals(format)) {
-            sendJsonResponse(overallResult, executionResults, null, response, 
includeDebug);
-        } else if (FORMAT_JSONP.equals(format)) {
-            String jsonpCallback = 
StringUtils.defaultIfEmpty(request.getParameter(PARAM_JSONP_CALLBACK.name), 
JSONP_CALLBACK_DEFAULT);
-            sendJsonResponse(overallResult, executionResults, jsonpCallback, 
response, includeDebug);
-        } else if (StringUtils.endsWith(format, FORMAT_TXT)) {
-            sendTxtResponse(overallResult, response, 
StringUtils.equals(format, FORMAT_VERBOSE_TXT), executionResults, includeDebug);
-        } else {
-            response.setContentType("text/plain");
-            response.getWriter().println("Invalid format " + format + " - 
supported formats: html|json|jsonp|txt|verbose.txt");
-        }
-    }
-
-    @Override
-    protected void doGet(final HttpServletRequest request, final 
HttpServletResponse response) throws ServletException, IOException {
-        String pathInfo = request.getPathInfo();
-        String format = splitFormat(pathInfo)[1];
-        if (StringUtils.isBlank(format)) {
-            // if not provided via extension use parameter or default
-            format = 
StringUtils.defaultIfEmpty(request.getParameter(PARAM_FORMAT.name), 
FORMAT_HTML);
-        }
-        doGet(request, response, format);
-    }
-
-    private String[] splitFormat(String pathInfo) {
-        for (String format : new String[] { FORMAT_HTML, FORMAT_JSON, 
FORMAT_JSONP, FORMAT_VERBOSE_TXT, FORMAT_TXT }) {
-            String formatWithDot = "." + format;
-            if (StringUtils.endsWith(pathInfo, formatWithDot)) {
-                return new String[] { 
StringUtils.substringBeforeLast(pathInfo, formatWithDot), format };
-            }
-        }
-        return new String[] { pathInfo, null };
-    }
-
-    private void sendTxtResponse(final Result overallResult, final 
HttpServletResponse response, boolean verbose,
-            List<HealthCheckExecutionResult> executionResults, boolean 
includeDebug) throws IOException {
-        response.setContentType(CONTENT_TYPE_TXT);
-        response.setCharacterEncoding("UTF-8");
-        if (verbose) {
-            
response.getWriter().write(verboseTxtSerializer.serialize(overallResult, 
executionResults, includeDebug));
-        } else {
-            response.getWriter().write(txtSerializer.serialize(overallResult));
-        }
-    }
-
-    private void sendJsonResponse(final Result overallResult, final 
List<HealthCheckExecutionResult> executionResults, final String jsonpCallback,
-            final HttpServletResponse response, boolean includeDebug)
-            throws IOException {
-        if (StringUtils.isNotBlank(jsonpCallback)) {
-            response.setContentType(CONTENT_TYPE_JSONP);
-        } else {
-            response.setContentType(CONTENT_TYPE_JSON);
-        }
-        response.setCharacterEncoding("UTF-8");
-
-        String resultJson = this.jsonSerializer.serialize(overallResult, 
executionResults, jsonpCallback, includeDebug);
-        PrintWriter writer = response.getWriter();
-        writer.append(resultJson);
-    }
-
-    private void sendHtmlResponse(final Result overallResult, final 
List<HealthCheckExecutionResult> executionResults,
-            final HttpServletRequest request, final HttpServletResponse 
response, boolean includeDebug)
-            throws IOException {
-        response.setContentType(CONTENT_TYPE_HTML);
-        response.setCharacterEncoding("UTF-8");
-        response.setHeader(STATUS_HEADER_NAME, overallResult.toString());
-        
response.getWriter().append(this.htmlSerializer.serialize(overallResult, 
executionResults, getHtmlHelpText(), includeDebug));
-    }
-
-    private void sendNoCacheHeaders(final HttpServletResponse response) {
-        response.setHeader(CACHE_CONTROL_KEY, CACHE_CONTROL_VALUE);
-    }
-
-    private void sendCorsHeaders(final HttpServletResponse response) {
-        if (StringUtils.isNotBlank(corsAccessControlAllowOrigin)) {
-            response.setHeader(CORS_ORIGIN_HEADER_NAME, 
corsAccessControlAllowOrigin);
-        }
-    }
-
-    private String getHtmlHelpText() {
-        final StringBuilder sb = new StringBuilder();
-        sb.append("<h3>Supported URL parameters</h3>\n");
-        for(Param p : PARAM_LIST) {
-            sb.append("<b>").append(p.name).append("</b>:");
-            sb.append(StringEscapeUtils.escapeHtml4(p.description));
-            sb.append("<br/>");
-        }
-        return sb.toString();
-    }
-
-    Map<Result.Status, Integer> getStatusMapping(String mappingStr) throws 
ServletException {
-        Map<Result.Status, Integer> statusMapping = new HashMap<Result.Status, 
Integer>();
-        try {
-            String[] bits = mappingStr.split("[,]");
-            for (String bit : bits) {
-                String[] tuple = bit.split("[:]");
-                statusMapping.put(Result.Status.valueOf(tuple[0]), 
Integer.parseInt(tuple[1]));
-            }
-        } catch (Exception e) {
-            throw new ServletException("Invalid parameter httpStatus=" + 
mappingStr + " " + e, e);
-        }
-
-        if (!statusMapping.containsKey(Result.Status.OK)) {
-            statusMapping.put(Result.Status.OK, 200);
-        }
-        if (!statusMapping.containsKey(Result.Status.WARN)) {
-            statusMapping.put(Result.Status.WARN, 
statusMapping.get(Result.Status.OK));
-        }
-        if (!statusMapping.containsKey(Result.Status.CRITICAL)) {
-            statusMapping.put(Result.Status.CRITICAL, 
statusMapping.get(Result.Status.WARN));
-        }
-        if (!statusMapping.containsKey(Result.Status.HEALTH_CHECK_ERROR)) {
-            statusMapping.put(Result.Status.HEALTH_CHECK_ERROR, 
statusMapping.get(Result.Status.CRITICAL));
-        }
-        return statusMapping;
-    }
-
-    private class ProxyServlet extends HttpServlet {
-
-        private final String format;
-
-        private ProxyServlet(final String format) {
-            this.format = format;
-        }
-
-        @Override
-        protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
throws ServletException, IOException {
-            HealthCheckExecutorServlet.this.doGet(req, resp, format);
-        }
-    }
-
-
-}
+/*
+ * 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 SF 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.hc.core.impl.servlet;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.hc.api.Result;
+import org.apache.sling.hc.api.Result.Status;
+import org.apache.sling.hc.api.execution.HealthCheckExecutionOptions;
+import org.apache.sling.hc.api.execution.HealthCheckExecutionResult;
+import org.apache.sling.hc.api.execution.HealthCheckExecutor;
+import org.apache.sling.hc.api.execution.HealthCheckSelector;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.metatype.annotations.Designate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** Servlet that triggers the health check executor to return results via http.
+ *
+ * Parameters:
+ * <ul>
+ * <li>tags: The health check tags to take into account
+ * <li>format: html|json|jsonp
+ * <li>includeDebug: If true, debug messages from result log are included.
+ * <li>callback: For jsonp, the JS callback function name (defaults to 
"processHealthCheckResults")
+ * <li>httpStatus: health check status to http status mapping in format 
httpStatus=WARN:418,CRITICAL:503,HEALTH_CHECK_ERROR:500.
+ * </ul>
+ *
+ * For omitted health check status values the next best code will be used 
(e.g. for httpStatus=CRITICAL:503 a result WARN will
+ * return 200, CRITICAL 503 and HEALTH_CHECK_ERROR also 503). By default all 
requests answer with an http status of 200.
+ * <p>
+ * Useful in combination with load balancers.
+ * <p>
+ * NOTE: This servlet registers directly (low-level) at the HttpService and is 
not processed by sling (better performance, fewer dependencies, no 
authentication required, 503 can be sent without the progress tracker 
information). */
+@Component(
+    configurationPolicy = ConfigurationPolicy.REQUIRE
+)
+@Designate(
+    ocd = HealthCheckExecutorServletConfiguration.class
+)
+public class HealthCheckExecutorServlet extends HttpServlet {
+    private static final long serialVersionUID = 8013511523994541848L;
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(HealthCheckExecutorServlet.class);
+    public static final String PARAM_SPLIT_REGEX = "[,;]+";
+
+    static class Param {
+        final String name;
+        final String description;
+        Param(String n, String d) {
+            name = n;
+            description = d;
+        }
+    }
+
+    static final Param PARAM_TAGS = new Param("tags",
+            "Comma-separated list of health checks tags to select - can also 
be specified via path, e.g. /system/health/tag1,tag2.json. Exclusions can be 
done by prepending '-' to the tag name");
+    static final Param PARAM_FORMAT = new Param("format", "Output format, 
html|json|jsonp|txt - an extension in the URL overrides this");
+    static final Param PARAM_HTTP_STATUS = new Param("httpStatus", "Specify 
HTTP result code, for example"
+            + " CRITICAL:503 (status 503 if result >= CRITICAL)"
+            + " or CRITICAL:503,HEALTH_CHECK_ERROR:500,OK:418 for more 
specific HTTP status");
+
+    static final Param PARAM_COMBINE_TAGS_WITH_OR = new 
Param("combineTagsWithOr", "Combine tags with OR, active by default. Set to 
false to combine with AND");
+    static final Param PARAM_FORCE_INSTANT_EXECUTION = new 
Param("forceInstantExecution",
+            "If true, forces instant execution by executing async health 
checks directly, circumventing the cache (2sec by default) of the 
HealthCheckExecutor");
+    static final Param PARAM_OVERRIDE_GLOBAL_TIMEOUT = new Param("timeout",
+            "(msec) a timeout status is returned for any health check still 
running after this period. Overrides the default HealthCheckExecutor timeout");
+
+    static final Param PARAM_INCLUDE_DEBUG = new Param("hcDebug", "Include the 
DEBUG output of the Health Checks");
+
+    static final Param PARAM_NAMES = new Param("names", "Comma-separated list 
of health check names to select. Exclusions can be done by prepending '-' to 
the health check name");
+
+    static final String JSONP_CALLBACK_DEFAULT = "processHealthCheckResults";
+    static final Param PARAM_JSONP_CALLBACK = new Param("callback", "name of 
the JSONP callback function to use, defaults to " + JSONP_CALLBACK_DEFAULT);
+
+    static final Param [] PARAM_LIST = { PARAM_TAGS, PARAM_NAMES, 
PARAM_FORMAT, PARAM_HTTP_STATUS, PARAM_COMBINE_TAGS_WITH_OR,
+        PARAM_FORCE_INSTANT_EXECUTION, PARAM_OVERRIDE_GLOBAL_TIMEOUT, 
PARAM_INCLUDE_DEBUG, PARAM_JSONP_CALLBACK};
+
+    static final String FORMAT_HTML = "html";
+    static final String FORMAT_JSON = "json";
+    static final String FORMAT_JSONP = "jsonp";
+    static final String FORMAT_TXT = "txt";
+    static final String FORMAT_VERBOSE_TXT = "verbose.txt";
+
+    private static final String CONTENT_TYPE_HTML = "text/html";
+    private static final String CONTENT_TYPE_TXT = "text/plain";
+    private static final String CONTENT_TYPE_JSON = "application/json";
+    private static final String CONTENT_TYPE_JSONP = "application/javascript";
+    private static final String STATUS_HEADER_NAME = "X-Health";
+
+    private static final String CACHE_CONTROL_KEY = "Cache-control";
+    private static final String CACHE_CONTROL_VALUE = "no-cache";
+
+    private String[] servletPaths;
+
+    private boolean disabled;
+
+    private String servletPath;
+
+    private String corsAccessControlAllowOrigin;
+
+    private static final String CORS_ORIGIN_HEADER_NAME = 
"Access-Control-Allow-Origin";
+
+
+    @Reference
+    private HttpService httpService;
+
+    @Reference
+    HealthCheckExecutor healthCheckExecutor;
+
+    @Reference
+    ResultHtmlSerializer htmlSerializer;
+
+    @Reference
+    ResultJsonSerializer jsonSerializer;
+
+    @Reference
+    ResultTxtSerializer txtSerializer;
+
+    @Reference
+    ResultTxtVerboseSerializer verboseTxtSerializer;
+
+    @Activate
+    protected final void activate(final 
HealthCheckExecutorServletConfiguration configuration) {
+        this.servletPath = configuration.servletPath();
+        this.disabled = configuration.disabled();
+        this.corsAccessControlAllowOrigin = 
configuration.cors_accessControlAllowOrigin();
+
+        Map<String, HttpServlet> servletsToRegister = new 
LinkedHashMap<String, HttpServlet>();
+        servletsToRegister.put(this.servletPath, this);
+        servletsToRegister.put(this.servletPath + "." + FORMAT_HTML, new 
ProxyServlet(FORMAT_HTML));
+        servletsToRegister.put(this.servletPath + "." + FORMAT_JSON, new 
ProxyServlet(FORMAT_JSON));
+        servletsToRegister.put(this.servletPath + "." + FORMAT_JSONP, new 
ProxyServlet(FORMAT_JSONP));
+        servletsToRegister.put(this.servletPath + "." + FORMAT_TXT, new 
ProxyServlet(FORMAT_TXT));
+        servletsToRegister.put(this.servletPath + "." + FORMAT_VERBOSE_TXT, 
new ProxyServlet(FORMAT_VERBOSE_TXT));
+
+        if (disabled) {
+            LOG.info("Health Check Servlet is disabled by configuration");
+            return;
+        }
+
+        for (final Map.Entry<String, HttpServlet> servlet : 
servletsToRegister.entrySet()) {
+            try {
+                LOG.debug("Registering {} to path {}", 
getClass().getSimpleName(), servlet.getKey());
+                this.httpService.registerServlet(servlet.getKey(), 
servlet.getValue(), null, null);
+            } catch (Exception e) {
+                LOG.error("Could not register health check servlet: " + e, e);
+            }
+        }
+        this.servletPaths = servletsToRegister.keySet().toArray(new String[0]);
+
+    }
+
+    @Deactivate
+    public void deactivate(final ComponentContext componentContext) {
+        if (disabled || this.servletPaths == null) {
+            return;
+        }
+
+        for (final String servletPath : this.servletPaths) {
+            try {
+                LOG.debug("Unregistering path {}", servletPath);
+                this.httpService.unregister(servletPath);
+            } catch (Exception e) {
+                LOG.error("Could not unregister health check servlet: " + e, 
e);
+            }
+        }
+        this.servletPaths = null;
+    }
+
+    protected void doGet(final HttpServletRequest request, final 
HttpServletResponse response, final String format) throws ServletException, 
IOException {
+        HealthCheckSelector selector = HealthCheckSelector.empty();
+        String pathInfo = request.getPathInfo();
+        String pathTokensStr = 
StringUtils.removeStart(splitFormat(pathInfo)[0], "/");
+
+        List<String> tags = new ArrayList<String>();
+        List<String> names = new ArrayList<String>();
+
+        if (StringUtils.isNotBlank(pathTokensStr)) {
+            String[] pathTokens = pathTokensStr.split(PARAM_SPLIT_REGEX);
+            for (String pathToken : pathTokens) {
+                if (pathToken.indexOf(' ') >= 0) {
+                    // token contains space. assume it is a name
+                    names.add(pathToken);
+                } else {
+                    tags.add(pathToken);
+                }
+            }
+        }
+        if (tags.size() == 0) {
+            // if not provided via path use parameter or default
+            tags = 
Arrays.asList(StringUtils.defaultIfEmpty(request.getParameter(PARAM_TAGS.name), 
"").split(PARAM_SPLIT_REGEX));
+        }
+        selector.withTags(tags.toArray(new String[0]));
+
+        if (names.size() == 0) {
+            // if not provided via path use parameter or default
+            names = 
Arrays.asList(StringUtils.defaultIfEmpty(request.getParameter(PARAM_NAMES.name),
 "").split(PARAM_SPLIT_REGEX));
+        }
+        selector.withNames(names.toArray(new String[0]));
+
+        final Boolean includeDebug = 
Boolean.valueOf(request.getParameter(PARAM_INCLUDE_DEBUG.name));
+        final Map<Result.Status, Integer> statusMapping = 
request.getParameter(PARAM_HTTP_STATUS.name) != null ? getStatusMapping(request
+                .getParameter(PARAM_HTTP_STATUS.name)) : null;
+
+        HealthCheckExecutionOptions executionOptions = new 
HealthCheckExecutionOptions();
+        
executionOptions.setCombineTagsWithOr(Boolean.valueOf(StringUtils.defaultString(request.getParameter(PARAM_COMBINE_TAGS_WITH_OR.name),
 "true")));
+        
executionOptions.setForceInstantExecution(Boolean.valueOf(request.getParameter(PARAM_FORCE_INSTANT_EXECUTION.name)));
+        String overrideGlobalTimeoutVal = 
request.getParameter(PARAM_OVERRIDE_GLOBAL_TIMEOUT.name);
+        if (StringUtils.isNumeric(overrideGlobalTimeoutVal)) {
+            
executionOptions.setOverrideGlobalTimeout(Integer.valueOf(overrideGlobalTimeoutVal));
+        }
+
+        List<HealthCheckExecutionResult> executionResults = 
this.healthCheckExecutor.execute(selector, executionOptions);
+
+        Result.Status mostSevereStatus = Result.Status.DEBUG;
+        for (HealthCheckExecutionResult executionResult : executionResults) {
+            Status status = executionResult.getHealthCheckResult().getStatus();
+            if (status.ordinal() > mostSevereStatus.ordinal()) {
+                mostSevereStatus = status;
+            }
+        }
+        Result overallResult = new Result(mostSevereStatus, "Overall status " 
+ mostSevereStatus);
+
+        sendNoCacheHeaders(response);
+        sendCorsHeaders(response);
+
+        if (statusMapping != null) {
+            Integer httpStatus = statusMapping.get(overallResult.getStatus());
+            response.setStatus(httpStatus);
+        }
+
+        if (FORMAT_HTML.equals(format)) {
+            sendHtmlResponse(overallResult, executionResults, request, 
response, includeDebug);
+        } else if (FORMAT_JSON.equals(format)) {
+            sendJsonResponse(overallResult, executionResults, null, response, 
includeDebug);
+        } else if (FORMAT_JSONP.equals(format)) {
+            String jsonpCallback = 
StringUtils.defaultIfEmpty(request.getParameter(PARAM_JSONP_CALLBACK.name), 
JSONP_CALLBACK_DEFAULT);
+            sendJsonResponse(overallResult, executionResults, jsonpCallback, 
response, includeDebug);
+        } else if (StringUtils.endsWith(format, FORMAT_TXT)) {
+            sendTxtResponse(overallResult, response, 
StringUtils.equals(format, FORMAT_VERBOSE_TXT), executionResults, includeDebug);
+        } else {
+            response.setContentType("text/plain");
+            response.getWriter().println("Invalid format " + format + " - 
supported formats: html|json|jsonp|txt|verbose.txt");
+        }
+    }
+
+    @Override
+    protected void doGet(final HttpServletRequest request, final 
HttpServletResponse response) throws ServletException, IOException {
+        String pathInfo = request.getPathInfo();
+        String format = splitFormat(pathInfo)[1];
+        if (StringUtils.isBlank(format)) {
+            // if not provided via extension use parameter or default
+            format = 
StringUtils.defaultIfEmpty(request.getParameter(PARAM_FORMAT.name), 
FORMAT_HTML);
+        }
+        doGet(request, response, format);
+    }
+
+    private String[] splitFormat(String pathInfo) {
+        for (String format : new String[] { FORMAT_HTML, FORMAT_JSON, 
FORMAT_JSONP, FORMAT_VERBOSE_TXT, FORMAT_TXT }) {
+            String formatWithDot = "." + format;
+            if (StringUtils.endsWith(pathInfo, formatWithDot)) {
+                return new String[] { 
StringUtils.substringBeforeLast(pathInfo, formatWithDot), format };
+            }
+        }
+        return new String[] { pathInfo, null };
+    }
+
+    private void sendTxtResponse(final Result overallResult, final 
HttpServletResponse response, boolean verbose,
+            List<HealthCheckExecutionResult> executionResults, boolean 
includeDebug) throws IOException {
+        response.setContentType(CONTENT_TYPE_TXT);
+        response.setCharacterEncoding("UTF-8");
+        if (verbose) {
+            
response.getWriter().write(verboseTxtSerializer.serialize(overallResult, 
executionResults, includeDebug));
+        } else {
+            response.getWriter().write(txtSerializer.serialize(overallResult));
+        }
+    }
+
+    private void sendJsonResponse(final Result overallResult, final 
List<HealthCheckExecutionResult> executionResults, final String jsonpCallback,
+            final HttpServletResponse response, boolean includeDebug)
+            throws IOException {
+        if (StringUtils.isNotBlank(jsonpCallback)) {
+            response.setContentType(CONTENT_TYPE_JSONP);
+        } else {
+            response.setContentType(CONTENT_TYPE_JSON);
+        }
+        response.setCharacterEncoding("UTF-8");
+
+        String resultJson = this.jsonSerializer.serialize(overallResult, 
executionResults, jsonpCallback, includeDebug);
+        PrintWriter writer = response.getWriter();
+        writer.append(resultJson);
+    }
+
+    private void sendHtmlResponse(final Result overallResult, final 
List<HealthCheckExecutionResult> executionResults,
+            final HttpServletRequest request, final HttpServletResponse 
response, boolean includeDebug)
+            throws IOException {
+        response.setContentType(CONTENT_TYPE_HTML);
+        response.setCharacterEncoding("UTF-8");
+        response.setHeader(STATUS_HEADER_NAME, overallResult.toString());
+        
response.getWriter().append(this.htmlSerializer.serialize(overallResult, 
executionResults, getHtmlHelpText(), includeDebug));
+    }
+
+    private void sendNoCacheHeaders(final HttpServletResponse response) {
+        response.setHeader(CACHE_CONTROL_KEY, CACHE_CONTROL_VALUE);
+    }
+
+    private void sendCorsHeaders(final HttpServletResponse response) {
+        if (StringUtils.isNotBlank(corsAccessControlAllowOrigin)) {
+            response.setHeader(CORS_ORIGIN_HEADER_NAME, 
corsAccessControlAllowOrigin);
+        }
+    }
+
+    private String getHtmlHelpText() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("<h3>Supported URL parameters</h3>\n");
+        for(Param p : PARAM_LIST) {
+            sb.append("<b>").append(p.name).append("</b>:");
+            sb.append(StringEscapeUtils.escapeHtml4(p.description));
+            sb.append("<br/>");
+        }
+        return sb.toString();
+    }
+
+    Map<Result.Status, Integer> getStatusMapping(String mappingStr) throws 
ServletException {
+        Map<Result.Status, Integer> statusMapping = new HashMap<Result.Status, 
Integer>();
+        try {
+            String[] bits = mappingStr.split("[,]");
+            for (String bit : bits) {
+                String[] tuple = bit.split("[:]");
+                statusMapping.put(Result.Status.valueOf(tuple[0]), 
Integer.parseInt(tuple[1]));
+            }
+        } catch (Exception e) {
+            throw new ServletException("Invalid parameter httpStatus=" + 
mappingStr + " " + e, e);
+        }
+
+        if (!statusMapping.containsKey(Result.Status.OK)) {
+            statusMapping.put(Result.Status.OK, 200);
+        }
+        if (!statusMapping.containsKey(Result.Status.WARN)) {
+            statusMapping.put(Result.Status.WARN, 
statusMapping.get(Result.Status.OK));
+        }
+        if (!statusMapping.containsKey(Result.Status.CRITICAL)) {
+            statusMapping.put(Result.Status.CRITICAL, 
statusMapping.get(Result.Status.WARN));
+        }
+        if (!statusMapping.containsKey(Result.Status.HEALTH_CHECK_ERROR)) {
+            statusMapping.put(Result.Status.HEALTH_CHECK_ERROR, 
statusMapping.get(Result.Status.CRITICAL));
+        }
+        return statusMapping;
+    }
+
+    private class ProxyServlet extends HttpServlet {
+
+        private final String format;
+
+        private ProxyServlet(final String format) {
+            this.format = format;
+        }
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
throws ServletException, IOException {
+            HealthCheckExecutorServlet.this.doGet(req, resp, format);
+        }
+    }
+
+
+}
diff --git 
a/src/main/java/org/apache/sling/hc/core/impl/servlet/ResultHtmlSerializer.java 
b/src/main/java/org/apache/sling/hc/core/impl/servlet/ResultHtmlSerializer.java
index e8cf059..d3c560b 100644
--- 
a/src/main/java/org/apache/sling/hc/core/impl/servlet/ResultHtmlSerializer.java
+++ 
b/src/main/java/org/apache/sling/hc/core/impl/servlet/ResultHtmlSerializer.java
@@ -1,157 +1,157 @@
-/*
- * 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 SF 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.hc.core.impl.servlet;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.Dictionary;
-import java.util.List;
-
-import org.apache.commons.lang3.StringEscapeUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.sling.commons.osgi.PropertiesUtil;
-import org.apache.sling.hc.api.Result;
-import org.apache.sling.hc.api.ResultLog.Entry;
-import org.apache.sling.hc.api.execution.HealthCheckExecutionResult;
-import org.apache.sling.hc.util.FormattingResultLog;
-import org.osgi.service.component.ComponentContext;
-import org.osgi.service.component.annotations.Activate;
-import org.osgi.service.component.annotations.Component;
-
-/** Serializes health check results into html format. */
-@Component(
-    service = ResultHtmlSerializer.class
-)
-public class ResultHtmlSerializer {
-
-    private String styleString;
-
-    @Activate
-    protected final void activate(final ResultHtmlSerializerConfiguration 
configuration) {
-        this.styleString = configuration.styleString();
-    }
-
-    public String serialize(final Result overallResult, final 
List<HealthCheckExecutionResult> executionResults, String escapedHelpText, 
boolean includeDebug) {
-
-        StringWriter stringWriter = new StringWriter();
-        PrintWriter writer = new PrintWriter(stringWriter);
-
-        writer.println("<html><head><title>System Health</title>" +
-                "<meta http-equiv='Content-Type' content='text/html; 
charset=UTF-8' /><style>" + styleString +
-                "</style></head><body><h1>System Health</h1>");
-
-        writer.println("<p><span class=\"" + 
getClassForStatus(overallResult.getStatus()) + "\"><strong>Overall Result: "
-                + overallResult.getStatus() + "</strong></span></p>");
-
-        final DateFormat dfShort = new SimpleDateFormat("HH:mm:ss.SSS");
-        final DateFormat dfLong = new SimpleDateFormat("yyyy-MM-dd HH:mm");
-
-        writer.println("<table id=\"healthCheckResults\" cellspacing=\"0\">");
-        writer.println(
-                "<thead><tr><th>Health Check <span 
style='color:gray'>(tags)</span></th><th>Status</th><th>Log</th><th>Finished 
At</th><th>Time</th></tr></thead>");
-        for (HealthCheckExecutionResult executionResult : executionResults) {
-            Result result = executionResult.getHealthCheckResult();
-            List<String> tags = 
executionResult.getHealthCheckMetadata().getTags();
-            boolean hasTags = tags != null && tags.size() > 0 && 
StringUtils.isNotBlank(tags.get(0));
-            writer.print("<tr class=\"" + 
getClassForStatus(result.getStatus()) + "\">");
-            writer.print("<td><p title=\"" + 
StringEscapeUtils.escapeHtml4(executionResult.getHealthCheckMetadata().getName())
 + "\">"
-                    + 
StringEscapeUtils.escapeHtml4(executionResult.getHealthCheckMetadata().getTitle())
 + "");
-            if (hasTags) {
-                writer.println("<br/><span style='color:gray'>" + 
StringEscapeUtils.escapeHtml4(StringUtils.join(tags, ", ")) + "</span>");
-            }
-            writer.println("</p></td>");
-            writer.println("<td style='font-weight:bold;'>" + 
StringEscapeUtils.escapeHtml4(result.getStatus().toString()) + "</td>");
-            writer.println("<td>");
-            boolean isFirst = true;
-
-            boolean isSingleResult = isSingleResult(result);
-
-            for (Entry entry : result) {
-               if(!includeDebug && entry.getStatus()==Result.Status.DEBUG) {
-                       continue;
-               }
-
-                if (isFirst) {
-                    isFirst = false;
-                } else {
-                    writer.println("<br/>\n");
-                }
-
-                boolean showStatus = !isSingleResult && 
entry.getStatus()!=Result.Status.DEBUG && entry.getStatus() 
!=Result.Status.INFO;
-
-                String message = 
StringEscapeUtils.escapeHtml4(entry.getMessage());
-                if(entry.getStatus()==Result.Status.DEBUG) {
-                       message = "<span style='color:gray'/>"+message + 
"</span>";
-                }
-                               writer.println((showStatus ? 
StringEscapeUtils.escapeHtml4(entry.getStatus().toString()) + " " : "") + 
message);
-
-                Exception exception = entry.getException();
-                if (exception != null) {
-                    writer.println("<span style='width:20px'/>" + 
StringEscapeUtils.escapeHtml4(exception.toString()));
-                    writer.println("<!--");
-                    exception.printStackTrace(writer);
-                    writer.println("-->");
-                }
-            }
-            writer.println("</td>");
-            Date finishedAt = executionResult.getFinishedAt();
-            writer.println("<td>" + (isToday(finishedAt) ? 
dfShort.format(finishedAt) : dfLong.format(finishedAt)) + "</td>");
-            writer.println("<td>" + 
FormattingResultLog.msHumanReadable(executionResult.getElapsedTimeInMs()) + 
"</td>");
-
-            writer.println("</tr>");
-        }
-        writer.println("</table>");
-
-        writer.println("<div class='helpText'>");
-        writer.println(escapedHelpText);
-        writer.println("</div>");
-        writer.println("</body></html>");
-
-        return stringWriter.toString();
-
-    }
-
-    private String getClassForStatus(final Result.Status status) {
-        return "status" + status.name();
-    }
-
-    private boolean isSingleResult(final Result result) {
-        int count = 0;
-        for (Entry entry : result) {
-            count++;
-            if (count > 1) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    private boolean isToday(Date date) {
-        Calendar cal1 = Calendar.getInstance();
-        Calendar cal2 = Calendar.getInstance();
-        cal2.setTime(date);
-        boolean isToday = cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
-                cal1.get(Calendar.DAY_OF_YEAR) == 
cal2.get(Calendar.DAY_OF_YEAR);
-        return isToday;
-
-    }
-}
+/*
+ * 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 SF 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.hc.core.impl.servlet;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Dictionary;
+import java.util.List;
+
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.hc.api.Result;
+import org.apache.sling.hc.api.ResultLog.Entry;
+import org.apache.sling.hc.api.execution.HealthCheckExecutionResult;
+import org.apache.sling.hc.util.FormattingResultLog;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+
+/** Serializes health check results into html format. */
+@Component(
+    service = ResultHtmlSerializer.class
+)
+public class ResultHtmlSerializer {
+
+    private String styleString;
+
+    @Activate
+    protected final void activate(final ResultHtmlSerializerConfiguration 
configuration) {
+        this.styleString = configuration.styleString();
+    }
+
+    public String serialize(final Result overallResult, final 
List<HealthCheckExecutionResult> executionResults, String escapedHelpText, 
boolean includeDebug) {
+
+        StringWriter stringWriter = new StringWriter();
+        PrintWriter writer = new PrintWriter(stringWriter);
+
+        writer.println("<html><head><title>System Health</title>" +
+                "<meta http-equiv='Content-Type' content='text/html; 
charset=UTF-8' /><style>" + styleString +
+                "</style></head><body><h1>System Health</h1>");
+
+        writer.println("<p><span class=\"" + 
getClassForStatus(overallResult.getStatus()) + "\"><strong>Overall Result: "
+                + overallResult.getStatus() + "</strong></span></p>");
+
+        final DateFormat dfShort = new SimpleDateFormat("HH:mm:ss.SSS");
+        final DateFormat dfLong = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+
+        writer.println("<table id=\"healthCheckResults\" cellspacing=\"0\">");
+        writer.println(
+                "<thead><tr><th>Health Check <span 
style='color:gray'>(tags)</span></th><th>Status</th><th>Log</th><th>Finished 
At</th><th>Time</th></tr></thead>");
+        for (HealthCheckExecutionResult executionResult : executionResults) {
+            Result result = executionResult.getHealthCheckResult();
+            List<String> tags = 
executionResult.getHealthCheckMetadata().getTags();
+            boolean hasTags = tags != null && tags.size() > 0 && 
StringUtils.isNotBlank(tags.get(0));
+            writer.print("<tr class=\"" + 
getClassForStatus(result.getStatus()) + "\">");
+            writer.print("<td><p title=\"" + 
StringEscapeUtils.escapeHtml4(executionResult.getHealthCheckMetadata().getName())
 + "\">"
+                    + 
StringEscapeUtils.escapeHtml4(executionResult.getHealthCheckMetadata().getTitle())
 + "");
+            if (hasTags) {
+                writer.println("<br/><span style='color:gray'>" + 
StringEscapeUtils.escapeHtml4(StringUtils.join(tags, ", ")) + "</span>");
+            }
+            writer.println("</p></td>");
+            writer.println("<td style='font-weight:bold;'>" + 
StringEscapeUtils.escapeHtml4(result.getStatus().toString()) + "</td>");
+            writer.println("<td>");
+            boolean isFirst = true;
+
+            boolean isSingleResult = isSingleResult(result);
+
+            for (Entry entry : result) {
+               if(!includeDebug && entry.getStatus()==Result.Status.DEBUG) {
+                       continue;
+               }
+
+                if (isFirst) {
+                    isFirst = false;
+                } else {
+                    writer.println("<br/>\n");
+                }
+
+                boolean showStatus = !isSingleResult && 
entry.getStatus()!=Result.Status.DEBUG && entry.getStatus() 
!=Result.Status.INFO;
+
+                String message = 
StringEscapeUtils.escapeHtml4(entry.getMessage());
+                if(entry.getStatus()==Result.Status.DEBUG) {
+                       message = "<span style='color:gray'/>"+message + 
"</span>";
+                }
+                               writer.println((showStatus ? 
StringEscapeUtils.escapeHtml4(entry.getStatus().toString()) + " " : "") + 
message);
+
+                Exception exception = entry.getException();
+                if (exception != null) {
+                    writer.println("<span style='width:20px'/>" + 
StringEscapeUtils.escapeHtml4(exception.toString()));
+                    writer.println("<!--");
+                    exception.printStackTrace(writer);
+                    writer.println("-->");
+                }
+            }
+            writer.println("</td>");
+            Date finishedAt = executionResult.getFinishedAt();
+            writer.println("<td>" + (isToday(finishedAt) ? 
dfShort.format(finishedAt) : dfLong.format(finishedAt)) + "</td>");
+            writer.println("<td>" + 
FormattingResultLog.msHumanReadable(executionResult.getElapsedTimeInMs()) + 
"</td>");
+
+            writer.println("</tr>");
+        }
+        writer.println("</table>");
+
+        writer.println("<div class='helpText'>");
+        writer.println(escapedHelpText);
+        writer.println("</div>");
+        writer.println("</body></html>");
+
+        return stringWriter.toString();
+
+    }
+
+    private String getClassForStatus(final Result.Status status) {
+        return "status" + status.name();
+    }
+
+    private boolean isSingleResult(final Result result) {
+        int count = 0;
+        for (Entry entry : result) {
+            count++;
+            if (count > 1) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean isToday(Date date) {
+        Calendar cal1 = Calendar.getInstance();
+        Calendar cal2 = Calendar.getInstance();
+        cal2.setTime(date);
+        boolean isToday = cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
+                cal1.get(Calendar.DAY_OF_YEAR) == 
cal2.get(Calendar.DAY_OF_YEAR);
+        return isToday;
+
+    }
+}
diff --git 
a/src/main/java/org/apache/sling/hc/core/impl/servlet/ResultJsonSerializer.java 
b/src/main/java/org/apache/sling/hc/core/impl/servlet/ResultJsonSerializer.java
index 7848d48..1616ce7 100644
--- 
a/src/main/java/org/apache/sling/hc/core/impl/servlet/ResultJsonSerializer.java
+++ 
b/src/main/java/org/apache/sling/hc/core/impl/servlet/ResultJsonSerializer.java
@@ -1,119 +1,119 @@
-/*
- * 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 SF 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.hc.core.impl.servlet;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.List;
-
-import javax.json.Json;
-import javax.json.JsonArrayBuilder;
-import javax.json.JsonException;
-import javax.json.JsonObject;
-import javax.json.JsonObjectBuilder;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.sling.hc.api.Result;
-import org.apache.sling.hc.api.ResultLog;
-import org.apache.sling.hc.api.execution.HealthCheckExecutionResult;
-import org.osgi.service.component.annotations.Component;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/** Serializes health check results into json format. */
-@Component(
-    service = ResultJsonSerializer.class
-)
-public class ResultJsonSerializer {
-
-    private static final Logger LOG = 
LoggerFactory.getLogger(ResultJsonSerializer.class);
-
-    static final String OVERALL_RESULT_KEY = "OverallResult";
-
-    public String serialize(final Result overallResult, final 
List<HealthCheckExecutionResult> executionResults, final String jsonpCallback,
-            boolean includeDebug) {
-
-        LOG.debug("Sending json response... ");
-
-        JsonObjectBuilder result = Json.createObjectBuilder();
-        try {
-
-            result.add("overallResult", overallResult.getStatus().toString());
-            JsonArrayBuilder resultsJsonArr = Json.createArrayBuilder();
-
-            for (HealthCheckExecutionResult healthCheckResult : 
executionResults) {
-                resultsJsonArr.add(getJsonForSimpleResult(healthCheckResult, 
includeDebug));
-            }
-
-            result.add("results", resultsJsonArr);
-        } catch (JsonException e) {
-            LOG.info("Could not serialize health check result: " + e, e);
-        }
-
-        StringWriter writer = new StringWriter();
-        Json.createGenerator(writer).write(result.build()).close();
-
-        String resultStr = writer.toString();
-
-        if (StringUtils.isNotBlank(jsonpCallback)) {
-            resultStr = jsonpCallback + "(" + resultStr + ");";
-        }
-
-        return resultStr;
-
-    }
-
-    private JsonObject getJsonForSimpleResult(final HealthCheckExecutionResult 
healthCheckResult, boolean includeDebug) {
-
-        JsonObjectBuilder result = Json.createObjectBuilder();
-
-        result.add("name", 
healthCheckResult.getHealthCheckMetadata().getName());
-        result.add("status", 
healthCheckResult.getHealthCheckResult().getStatus().toString());
-        result.add("timeInMs", healthCheckResult.getElapsedTimeInMs());
-        result.add("finishedAt", healthCheckResult.getFinishedAt().toString());
-        JsonArrayBuilder tagsArray = Json.createArrayBuilder();
-        for (final String tag : 
healthCheckResult.getHealthCheckMetadata().getTags()) {
-            tagsArray.add(tag);
-        }
-        result.add("tags", tagsArray);
-
-        JsonArrayBuilder messagesArr = Json.createArrayBuilder();
-
-        for (ResultLog.Entry entry : healthCheckResult.getHealthCheckResult()) 
{
-            if (!includeDebug && entry.getStatus() == Result.Status.DEBUG) {
-                continue;
-            }
-            JsonObjectBuilder jsonEntry = Json.createObjectBuilder();
-            jsonEntry.add("status", entry.getStatus().toString());
-            jsonEntry.add("message", entry.getMessage());
-            Exception exception = entry.getException();
-            if (exception != null) {
-                StringWriter stringWriter = new StringWriter();
-                exception.printStackTrace(new PrintWriter(stringWriter));
-                jsonEntry.add("exception", stringWriter.toString());
-            }
-            messagesArr.add(jsonEntry);
-        }
-
-        result.add("messages", messagesArr);
-
-
-        return result.build();
-    }
-
-}
+/*
+ * 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 SF 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.hc.core.impl.servlet;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.List;
+
+import javax.json.Json;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonException;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.hc.api.Result;
+import org.apache.sling.hc.api.ResultLog;
+import org.apache.sling.hc.api.execution.HealthCheckExecutionResult;
+import org.osgi.service.component.annotations.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** Serializes health check results into json format. */
+@Component(
+    service = ResultJsonSerializer.class
+)
+public class ResultJsonSerializer {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(ResultJsonSerializer.class);
+
+    static final String OVERALL_RESULT_KEY = "OverallResult";
+
+    public String serialize(final Result overallResult, final 
List<HealthCheckExecutionResult> executionResults, final String jsonpCallback,
+            boolean includeDebug) {
+
+        LOG.debug("Sending json response... ");
+
+        JsonObjectBuilder result = Json.createObjectBuilder();
+        try {
+
+            result.add("overallResult", overallResult.getStatus().toString());
+            JsonArrayBuilder resultsJsonArr = Json.createArrayBuilder();
+
+            for (HealthCheckExecutionResult healthCheckResult : 
executionResults) {
+                resultsJsonArr.add(getJsonForSimpleResult(healthCheckResult, 
includeDebug));
+            }
+
+            result.add("results", resultsJsonArr);
+        } catch (JsonException e) {
+            LOG.info("Could not serialize health check result: " + e, e);
+        }
+
+        StringWriter writer = new StringWriter();
+        Json.createGenerator(writer).write(result.build()).close();
+
+        String resultStr = writer.toString();
+
+        if (StringUtils.isNotBlank(jsonpCallback)) {
+            resultStr = jsonpCallback + "(" + resultStr + ");";
+        }
+
+        return resultStr;
+
+    }
+
+    private JsonObject getJsonForSimpleResult(final HealthCheckExecutionResult 
healthCheckResult, boolean includeDebug) {
+
+        JsonObjectBuilder result = Json.createObjectBuilder();
+
+        result.add("name", 
healthCheckResult.getHealthCheckMetadata().getName());
+        result.add("status", 
healthCheckResult.getHealthCheckResult().getStatus().toString());
+        result.add("timeInMs", healthCheckResult.getElapsedTimeInMs());
+        result.add("finishedAt", healthCheckResult.getFinishedAt().toString());
+        JsonArrayBuilder tagsArray = Json.createArrayBuilder();
+        for (final String tag : 
healthCheckResult.getHealthCheckMetadata().getTags()) {
+            tagsArray.add(tag);
+        }
+        result.add("tags", tagsArray);
+
+        JsonArrayBuilder messagesArr = Json.createArrayBuilder();
+
+        for (ResultLog.Entry entry : healthCheckResult.getHealthCheckResult()) 
{
+            if (!includeDebug && entry.getStatus() == Result.Status.DEBUG) {
+                continue;
+            }
+            JsonObjectBuilder jsonEntry = Json.createObjectBuilder();
+            jsonEntry.add("status", entry.getStatus().toString());
+            jsonEntry.add("message", entry.getMessage());
+            Exception exception = entry.getException();
+            if (exception != null) {
+                StringWriter stringWriter = new StringWriter();
+                exception.printStackTrace(new PrintWriter(stringWriter));
+                jsonEntry.add("exception", stringWriter.toString());
+            }
+            messagesArr.add(jsonEntry);
+        }
+
+        result.add("messages", messagesArr);
+
+
+        return result.build();
+    }
+
+}
diff --git 
a/src/main/java/org/apache/sling/hc/core/impl/servlet/ResultTxtSerializer.java 
b/src/main/java/org/apache/sling/hc/core/impl/servlet/ResultTxtSerializer.java
index e8f9c57..9c4d673 100644
--- 
a/src/main/java/org/apache/sling/hc/core/impl/servlet/ResultTxtSerializer.java
+++ 
b/src/main/java/org/apache/sling/hc/core/impl/servlet/ResultTxtSerializer.java
@@ -1,32 +1,32 @@
-/*
- * 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 SF 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.hc.core.impl.servlet;
-
-import org.apache.sling.hc.api.Result;
-import org.osgi.service.component.annotations.Component;
-
-/** Serializes health check results into a simple text message (ideal to be 
used by a load balancer that would discard
- * further information). */
-@Component(
-    service = ResultTxtSerializer.class
-)
-public class ResultTxtSerializer {
-    public String serialize(final Result overallResult) {
-        return overallResult.getStatus().toString();
-    }
-}
+/*
+ * 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 SF 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.hc.core.impl.servlet;
+
+import org.apache.sling.hc.api.Result;
+import org.osgi.service.component.annotations.Component;
+
+/** Serializes health check results into a simple text message (ideal to be 
used by a load balancer that would discard
+ * further information). */
+@Component(
+    service = ResultTxtSerializer.class
+)
+public class ResultTxtSerializer {
+    public String serialize(final Result overallResult) {
+        return overallResult.getStatus().toString();
+    }
+}
diff --git 
a/src/main/java/org/apache/sling/hc/core/impl/servlet/ResultTxtVerboseSerializer.java
 
b/src/main/java/org/apache/sling/hc/core/impl/servlet/ResultTxtVerboseSerializer.java
index 9fcac59..a8e46ef 100644
--- 
a/src/main/java/org/apache/sling/hc/core/impl/servlet/ResultTxtVerboseSerializer.java
+++ 
b/src/main/java/org/apache/sling/hc/core/impl/servlet/ResultTxtVerboseSerializer.java
@@ -1,137 +1,137 @@
-/*
- * 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 SF 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.hc.core.impl.servlet;
-
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.List;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.text.WordUtils;
-import org.apache.sling.hc.api.Result;
-import org.apache.sling.hc.api.ResultLog;
-import org.apache.sling.hc.api.execution.HealthCheckExecutionResult;
-import org.apache.sling.hc.util.FormattingResultLog;
-import org.osgi.service.component.annotations.Activate;
-import org.osgi.service.component.annotations.Component;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/** Serializes health check results into a verbose text message. */
-@Component(
-    service = ResultTxtVerboseSerializer.class
-)
-public class ResultTxtVerboseSerializer {
-
-    private static final Logger LOG = 
LoggerFactory.getLogger(ResultTxtVerboseSerializer.class);
-
-    private static final String NEWLINE = "\n"; // not using system prop 
'line.separator' as not the local but the calling system is relevant.
-
-    private int totalWidth;
-
-    private int colWidthName;
-
-    private int colWidthResult;
-
-    private int colWidthTiming;
-
-    private int colWidthWithoutLog;
-    private int colWidthLog;
-
-    @Activate
-    protected final void activate(final 
ResultTxtVerboseSerializerConfiguration configuration) {
-        this.totalWidth = configuration.totalWidth();
-        this.colWidthName = configuration.colWidthName();
-        this.colWidthResult = configuration.colWidthResult();
-        this.colWidthTiming = configuration.colWidthTiming();
-        colWidthWithoutLog = colWidthName + colWidthResult + colWidthTiming;
-        colWidthLog = totalWidth - colWidthWithoutLog;
-    }
-
-    public String serialize(final Result overallResult, final 
List<HealthCheckExecutionResult> executionResults, boolean includeDebug) {
-
-        LOG.debug("Sending verbose txt response... ");
-
-        StringBuilder resultStr = new StringBuilder();
-
-        resultStr.append(StringUtils.repeat("-", totalWidth) + NEWLINE);
-        resultStr.append(StringUtils.center("Overall Health Result: " + 
overallResult.getStatus().toString(), totalWidth) + NEWLINE);
-        resultStr.append(StringUtils.repeat("-", totalWidth) + NEWLINE);
-        resultStr.append(StringUtils.rightPad("Name", colWidthName));
-        resultStr.append(StringUtils.rightPad("Result", colWidthResult));
-        resultStr.append(StringUtils.rightPad("Timing", colWidthTiming));
-        resultStr.append("Logs" + NEWLINE);
-        resultStr.append(StringUtils.repeat("-", totalWidth) + NEWLINE);
-
-        final DateFormat dfShort = new SimpleDateFormat("HH:mm:ss.SSS");
-
-        for (HealthCheckExecutionResult healthCheckResult : executionResults) {
-            appendVerboseTxtForResult(resultStr, healthCheckResult, 
includeDebug, dfShort);
-        }
-        resultStr.append(StringUtils.repeat("-", totalWidth) + NEWLINE);
-
-        return resultStr.toString();
-
-    }
-
-    private void appendVerboseTxtForResult(StringBuilder resultStr, 
HealthCheckExecutionResult healthCheckResult, boolean includeDebug, DateFormat 
dfShort) {
-
-        String wrappedName = 
WordUtils.wrap(healthCheckResult.getHealthCheckMetadata().getName(), 
colWidthName);
-
-        String relevantNameStringForPadding = 
StringUtils.contains(wrappedName, "\n") ? 
StringUtils.substringAfterLast(wrappedName, "\n") : wrappedName;
-        int paddingSize = colWidthName - relevantNameStringForPadding.length();
-
-        resultStr.append(wrappedName + StringUtils.repeat(" ", paddingSize));
-        
resultStr.append(StringUtils.rightPad(healthCheckResult.getHealthCheckResult().getStatus().toString(),
 colWidthResult));
-        resultStr.append(StringUtils.rightPad("[" + 
dfShort.format(healthCheckResult.getFinishedAt())
-                + "|" + 
FormattingResultLog.msHumanReadable(healthCheckResult.getElapsedTimeInMs()) + 
"]", colWidthTiming));
-
-        boolean isFirst = true;
-        for (ResultLog.Entry logEntry : 
healthCheckResult.getHealthCheckResult()) {
-            if (!includeDebug && logEntry.getStatus() == Result.Status.DEBUG) {
-                continue;
-            }
-            if(isFirst) {
-                isFirst = false;
-            } else {
-                resultStr.append(StringUtils.repeat(" ", colWidthWithoutLog));
-            }
-
-            String oneLineMessage = getStatusForTxtLog(logEntry) + 
logEntry.getMessage();
-            String messageToPrint = WordUtils.wrap(oneLineMessage, 
colWidthLog, "\n" + StringUtils.repeat(" ", colWidthWithoutLog), true);
-
-            resultStr.append(messageToPrint);
-            resultStr.append(NEWLINE);
-        }
-
-        if (isFirst) {
-            // no log entry exists, ensure newline
-            resultStr.append(NEWLINE);
-        }
-
-    }
-
-    private String getStatusForTxtLog(ResultLog.Entry logEntry) {
-        if (logEntry.getStatus() == Result.Status.OK || logEntry.getStatus() 
== Result.Status.INFO) {
-            return "";
-        } else {
-            return logEntry.getStatus().toString() + " ";
-        }
-    }
-
-}
+/*
+ * 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 SF 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.hc.core.impl.servlet;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.text.WordUtils;
+import org.apache.sling.hc.api.Result;
+import org.apache.sling.hc.api.ResultLog;
+import org.apache.sling.hc.api.execution.HealthCheckExecutionResult;
+import org.apache.sling.hc.util.FormattingResultLog;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** Serializes health check results into a verbose text message. */
+@Component(
+    service = ResultTxtVerboseSerializer.class
+)
+public class ResultTxtVerboseSerializer {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(ResultTxtVerboseSerializer.class);
+
+    private static final String NEWLINE = "\n"; // not using system prop 
'line.separator' as not the local but the calling system is relevant.
+
+    private int totalWidth;
+
+    private int colWidthName;
+
+    private int colWidthResult;
+
+    private int colWidthTiming;
+
+    private int colWidthWithoutLog;
+    private int colWidthLog;
+
+    @Activate
+    protected final void activate(final 
ResultTxtVerboseSerializerConfiguration configuration) {
+        this.totalWidth = configuration.totalWidth();
+        this.colWidthName = configuration.colWidthName();
+        this.colWidthResult = configuration.colWidthResult();
+        this.colWidthTiming = configuration.colWidthTiming();
+        colWidthWithoutLog = colWidthName + colWidthResult + colWidthTiming;
+        colWidthLog = totalWidth - colWidthWithoutLog;
+    }
+
+    public String serialize(final Result overallResult, final 
List<HealthCheckExecutionResult> executionResults, boolean includeDebug) {
+
+        LOG.debug("Sending verbose txt response... ");
+
+        StringBuilder resultStr = new StringBuilder();
+
+        resultStr.append(StringUtils.repeat("-", totalWidth) + NEWLINE);
+        resultStr.append(StringUtils.center("Overall Health Result: " + 
overallResult.getStatus().toString(), totalWidth) + NEWLINE);
+        resultStr.append(StringUtils.repeat("-", totalWidth) + NEWLINE);
+        resultStr.append(StringUtils.rightPad("Name", colWidthName));
+        resultStr.append(StringUtils.rightPad("Result", colWidthResult));
+        resultStr.append(StringUtils.rightPad("Timing", colWidthTiming));
+        resultStr.append("Logs" + NEWLINE);
+        resultStr.append(StringUtils.repeat("-", totalWidth) + NEWLINE);
+
+        final DateFormat dfShort = new SimpleDateFormat("HH:mm:ss.SSS");
+
+        for (HealthCheckExecutionResult healthCheckResult : executionResults) {
+            appendVerboseTxtForResult(resultStr, healthCheckResult, 
includeDebug, dfShort);
+        }
+        resultStr.append(StringUtils.repeat("-", totalWidth) + NEWLINE);
+
+        return resultStr.toString();
+
+    }
+
+    private void appendVerboseTxtForResult(StringBuilder resultStr, 
HealthCheckExecutionResult healthCheckResult, boolean includeDebug, DateFormat 
dfShort) {
+
+        String wrappedName = 
WordUtils.wrap(healthCheckResult.getHealthCheckMetadata().getName(), 
colWidthName);
+
+        String relevantNameStringForPadding = 
StringUtils.contains(wrappedName, "\n") ? 
StringUtils.substringAfterLast(wrappedName, "\n") : wrappedName;
+        int paddingSize = colWidthName - relevantNameStringForPadding.length();
+
+        resultStr.append(wrappedName + StringUtils.repeat(" ", paddingSize));
+        
resultStr.append(StringUtils.rightPad(healthCheckResult.getHealthCheckResult().getStatus().toString(),
 colWidthResult));
+        resultStr.append(StringUtils.rightPad("[" + 
dfShort.format(healthCheckResult.getFinishedAt())
+                + "|" + 
FormattingResultLog.msHumanReadable(healthCheckResult.getElapsedTimeInMs()) + 
"]", colWidthTiming));
+
+        boolean isFirst = true;
+        for (ResultLog.Entry logEntry : 
healthCheckResult.getHealthCheckResult()) {
+            if (!includeDebug && logEntry.getStatus() == Result.Status.DEBUG) {
+                continue;
+            }
+            if(isFirst) {
+                isFirst = false;
+            } else {
+                resultStr.append(StringUtils.repeat(" ", colWidthWithoutLog));
+            }
+
+            String oneLineMessage = getStatusForTxtLog(logEntry) + 
logEntry.getMessage();
+            String messageToPrint = WordUtils.wrap(oneLineMessage, 
colWidthLog, "\n" + StringUtils.repeat(" ", colWidthWithoutLog), true);
+
+            resultStr.append(messageToPrint);
+            resultStr.append(NEWLINE);
+        }
+
+        if (isFirst) {
+            // no log entry exists, ensure newline
+            resultStr.append(NEWLINE);
+        }
+
+    }
+
+    private String getStatusForTxtLog(ResultLog.Entry logEntry) {
+        if (logEntry.getStatus() == Result.Status.OK || logEntry.getStatus() 
== Result.Status.INFO) {
+            return "";
+        } else {
+            return logEntry.getStatus().toString() + " ";
+        }
+    }
+
+}

-- 
To stop receiving notification emails like this one, please contact
o...@apache.org.

Reply via email to