You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2013/06/05 17:44:33 UTC

svn commit: r1489927 - in /sling/trunk/contrib/extensions/healthcheck: hc-core/src/main/java/org/apache/sling/hc/util/ hc-core/src/test/java/org/apache/sling/hc/util/ hc-sling/ hc-sling/src/main/java/org/apache/sling/hc/sling/api/ hc-sling/src/main/jav...

Author: bdelacretaz
Date: Wed Jun  5 15:44:32 2013
New Revision: 1489927

URL: http://svn.apache.org/r1489927
Log:
SLING-2822 - webconsole plugin added

Added:
    sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/HtmlResultRendererImpl.java   (with props)
    sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/SlingHealthCheckWebconsolePlugin.java   (with props)
    sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/WebConsoleHelper.java   (with props)
    sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/resources/
    sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/resources/res/
    sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/resources/res/ui/
    sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/resources/res/ui/healthcheck.css   (with props)
Removed:
    sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/api/JsonResultRenderer.java
Modified:
    sling/trunk/contrib/extensions/healthcheck/hc-core/src/main/java/org/apache/sling/hc/util/TaggedRuleFilter.java
    sling/trunk/contrib/extensions/healthcheck/hc-core/src/test/java/org/apache/sling/hc/util/TaggedRuleFilterTest.java
    sling/trunk/contrib/extensions/healthcheck/hc-sling/pom.xml
    sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/JsonResultRendererImpl.java
    sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/RulesExecutionPermission.java
    sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/RulesResourceParserImpl.java
    sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/SlingHealthCheckServlet.java
    sling/trunk/contrib/extensions/healthcheck/hc-sling/src/test/java/org/apache/sling/hc/sling/MockResolver.java
    sling/trunk/contrib/extensions/healthcheck/hc-sling/src/test/java/org/apache/sling/hc/sling/MockResource.java
    sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/RepositoryPresentTest.json
    sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/ResourcesExistTest-checkAppsExist.json
    sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/ResourcesExistTest.json
    sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/junit-sling-all.json
    sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/script-that-fails.jsp

Modified: sling/trunk/contrib/extensions/healthcheck/hc-core/src/main/java/org/apache/sling/hc/util/TaggedRuleFilter.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/hc-core/src/main/java/org/apache/sling/hc/util/TaggedRuleFilter.java?rev=1489927&r1=1489926&r2=1489927&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/healthcheck/hc-core/src/main/java/org/apache/sling/hc/util/TaggedRuleFilter.java (original)
+++ sling/trunk/contrib/extensions/healthcheck/hc-core/src/main/java/org/apache/sling/hc/util/TaggedRuleFilter.java Wed Jun  5 15:44:32 2013
@@ -17,22 +17,27 @@
  */
 package org.apache.sling.hc.util;
 
-import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.apache.sling.hc.api.Rule;
 import org.apache.sling.hc.api.RuleFilter;
 
 /** {@link RulerFilter} that accepts {@link Rule} that have certain tags */
 public class TaggedRuleFilter implements RuleFilter {
-    private String [] tags;
+    private final List<String> tags = new ArrayList<String>();
     
     /** Create a RuleFilter that selects Rules
      *  having all supplied tags (lowercased)
      */
-    public TaggedRuleFilter(String ...tags) {
-        this.tags = tags;
-        for(int i=0 ; i < tags.length; i++) {
-            tags[i] = tags[i].toLowerCase();
+    public TaggedRuleFilter(String ...inputTags) {
+        
+        // Trim and ignore empty tags
+        for(int i=0 ; i < inputTags.length; i++) {
+            String tag = inputTags[i].trim();
+            if(tag.length() > 0) {
+                tags.add(tag.toLowerCase());
+            }
         }
     }
     
@@ -47,6 +52,6 @@ public class TaggedRuleFilter implements
     
     @Override
     public String toString() {
-        return getClass().getSimpleName() + ", tags=" + Arrays.asList(tags);
+        return getClass().getSimpleName() + ", tags=" + tags;
     }
 }

Modified: sling/trunk/contrib/extensions/healthcheck/hc-core/src/test/java/org/apache/sling/hc/util/TaggedRuleFilterTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/hc-core/src/test/java/org/apache/sling/hc/util/TaggedRuleFilterTest.java?rev=1489927&r1=1489926&r2=1489927&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/healthcheck/hc-core/src/test/java/org/apache/sling/hc/util/TaggedRuleFilterTest.java (original)
+++ sling/trunk/contrib/extensions/healthcheck/hc-core/src/test/java/org/apache/sling/hc/util/TaggedRuleFilterTest.java Wed Jun  5 15:44:32 2013
@@ -52,6 +52,14 @@ public class TaggedRuleFilterTest {
     }
     
     @Test
+    public void testTrimAndIgnoreTags() {
+        final TaggedRuleFilter f = new TaggedRuleFilter("", "\nfoo\t", "", "bar");
+        assertFalse(f.accept(notags));
+        assertTrue(f.accept(foobar));
+        assertFalse(f.accept(foo));
+    }
+    
+    @Test
     public void testFoobarLowercaseTagsFilter() {
         final TaggedRuleFilter f = new TaggedRuleFilter("Foo", "BAR");
         assertFalse(f.accept(notags));

Modified: sling/trunk/contrib/extensions/healthcheck/hc-sling/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/hc-sling/pom.xml?rev=1489927&r1=1489926&r2=1489927&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/healthcheck/hc-sling/pom.xml (original)
+++ sling/trunk/contrib/extensions/healthcheck/hc-sling/pom.xml Wed Jun  5 15:44:32 2013
@@ -80,7 +80,7 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.api</artifactId>
-            <version>2.0.6</version>
+            <version>2.4.0</version>
             <scope>provided</scope>
         </dependency>
         <dependency>

Added: sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/HtmlResultRendererImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/HtmlResultRendererImpl.java?rev=1489927&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/HtmlResultRendererImpl.java (added)
+++ sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/HtmlResultRendererImpl.java Wed Jun  5 15:44:32 2013
@@ -0,0 +1,87 @@
+/*
+ * 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.sling.impl;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sling.api.request.ResponseUtil;
+import org.apache.sling.hc.api.EvaluationResult;
+
+/** Renders a List of EvaluationResult in HTML */
+public class HtmlResultRendererImpl implements SlingHealthCheckServlet.Renderer {
+
+    public String getExtension() {
+        return "html";
+    }
+    
+    public String getContentType() {
+        return "text/html";
+    }
+    
+    public void render(List<EvaluationResult> results, Writer output) throws IOException {
+        final PrintWriter pw = new PrintWriter(output);
+        final WebConsoleHelper c = new WebConsoleHelper(pw);
+        pw.println("<table class='content healthcheck' cellpadding='0' cellspacing='0' width='100%'>");
+        for(EvaluationResult r : results) {
+            c.titleHtml(r.getRule().toString(), null);
+            
+            if(!r.getRule().getTags().isEmpty()) {
+                dataRow(c, "Tags", ResponseUtil.escapeXml(r.getRule().getTags().toString()));
+            }
+            
+            if(!r.getRule().getInfo().isEmpty()) {
+                final StringBuilder sb = new StringBuilder();
+                for(Map.Entry<String, Object> e : r.getRule().getInfo().entrySet()) {
+                    sb.append(ResponseUtil.escapeXml(e.getKey()))
+                    .append(":")
+                    .append(ResponseUtil.escapeXml(e.getValue().toString()))
+                    .append("<br/>");
+                }
+                dataRow(c, "Info", sb.toString());
+            }
+            
+            if(r.anythingToReport()) {
+                final StringBuilder sb = new StringBuilder();
+                for(EvaluationResult.LogMessage msg : r.getLogMessages()) {
+                    sb.append("<div class='log").append(msg.getLevel().toString()).append("'>");
+                    sb.append(msg.getLevel().toString())
+                    .append(" ")
+                    .append(ResponseUtil.escapeXml(msg.getMessage()))
+                    .append("</div>");
+                }
+                dataRow(c, "Log", sb.toString());
+            } else {
+                dataRow(c, "Log", "<span class='nothingToReport'>Nothing to report</a>");
+            }
+        }
+        pw.println("</table>");
+    }
+    
+    private void dataRow(WebConsoleHelper c, String label, String content) {
+        c.tr();
+        c.tdLabel(ResponseUtil.escapeXml(label));
+        c.tdContent();
+        c.writer().println(content);
+        c.closeTd();
+        c.closeTr();
+    }
+}

Propchange: sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/HtmlResultRendererImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/HtmlResultRendererImpl.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Modified: sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/JsonResultRendererImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/JsonResultRendererImpl.java?rev=1489927&r1=1489926&r2=1489927&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/JsonResultRendererImpl.java (original)
+++ sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/JsonResultRendererImpl.java Wed Jun  5 15:44:32 2013
@@ -22,21 +22,21 @@ import java.io.Writer;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.commons.json.JSONException;
 import org.apache.sling.commons.json.io.JSONWriter;
 import org.apache.sling.hc.api.EvaluationResult;
-import org.apache.sling.hc.sling.api.JsonResultRenderer;
 
-/** Renders a List of EvaluationResult in JSON. See unit tests
- *  for details.
- */
-@Component
-@Service(value=JsonResultRenderer.class)
-public class JsonResultRendererImpl implements JsonResultRenderer {
+/** Renders a List of EvaluationResult in JSON */
+public class JsonResultRendererImpl implements SlingHealthCheckServlet.Renderer {
+    
+    public String getExtension() {
+        return "json";
+    }
+    
+    public String getContentType() {
+        return "application/json";
+    }
     
-    @Override
     public void render(List<EvaluationResult> results, Writer output) throws IOException {
         final JSONWriter w = new JSONWriter(output);
         w.setTidy(true);

Modified: sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/RulesExecutionPermission.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/RulesExecutionPermission.java?rev=1489927&r1=1489926&r2=1489927&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/RulesExecutionPermission.java (original)
+++ sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/RulesExecutionPermission.java Wed Jun  5 15:44:32 2013
@@ -41,6 +41,10 @@ public class RulesExecutionPermission {
     
     /** Check if the user to which r points is authorized to execute our Rules */
     public void checkPermission(Resource r) throws RepositoryException {
+        if(r == null) {
+            throw new AccessDeniedException("No Resource, cannot check permissions");
+        }
+        
         final Session s = r.getResourceResolver().adaptTo(Session.class);
         if(s == null) {
             log.warn("Adapting {} to a Session returns null, cannot check permissions", r);

Modified: sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/RulesResourceParserImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/RulesResourceParserImpl.java?rev=1489927&r1=1489926&r2=1489927&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/RulesResourceParserImpl.java (original)
+++ sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/RulesResourceParserImpl.java Wed Jun  5 15:44:32 2013
@@ -96,7 +96,7 @@ public class RulesResourceParserImpl imp
 
         // else convert using available RuleBuilders if suitable
         final ValueMap props = r.adaptTo(ValueMap.class);
-        if(props.containsKey(NAMESPACE) && props.containsKey(RULE_NAME)) {
+        if(props != null && props.containsKey(NAMESPACE) && props.containsKey(RULE_NAME)) {
             for(RuleBuilder b : healthcheck.getRuleBuilders()) {
                 // basic properties
                 final Rule rule = b.buildRule(

Modified: sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/SlingHealthCheckServlet.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/SlingHealthCheckServlet.java?rev=1489927&r1=1489926&r2=1489927&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/SlingHealthCheckServlet.java (original)
+++ sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/SlingHealthCheckServlet.java Wed Jun  5 15:44:32 2013
@@ -18,24 +18,32 @@
 package org.apache.sling.hc.sling.impl;
 
 import java.io.IOException;
+import java.io.Writer;
 import java.util.ArrayList;
 import java.util.List;
 
 import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
 
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.sling.SlingServlet;
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolverFactory;
 import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
+import org.apache.sling.hc.api.EvaluationResult;
 import org.apache.sling.hc.api.HealthCheckFacade;
 import org.apache.sling.hc.api.RulesEngine;
-import org.apache.sling.hc.sling.api.JsonResultRenderer;
 import org.apache.sling.hc.sling.api.RulesResourceParser;
 import org.apache.sling.hc.util.TaggedRuleFilter;
+import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+
 /** Sling Servlet that renders a Resource that contains health check rules 
  *  definitions, after evaluating the rules.
  *  {@link RulesResourceParser} defines the resource format, and {@link JsonResultRenderer}
@@ -43,7 +51,7 @@ import org.slf4j.LoggerFactory;
  */
 @SuppressWarnings("serial")
 @SlingServlet(
-        extensions="json",
+        extensions={"json","html"},
         resourceTypes="sling/healthcheck/rules",
         methods="GET",
         selectors=SlingHealthCheckServlet.HC_SELECTOR)
@@ -52,6 +60,7 @@ public class SlingHealthCheckServlet ext
     public static final String HC_SELECTOR = "healthcheck";
     
     private final Logger log = LoggerFactory.getLogger(getClass());
+    private SlingHealthCheckWebconsolePlugin consolePlugin;
     
     @Reference
     private HealthCheckFacade healthcheck;
@@ -60,19 +69,54 @@ public class SlingHealthCheckServlet ext
     private RulesResourceParser parser;
     
     @Reference
-    private JsonResultRenderer renderer;
+    private ResourceResolverFactory resourceResolverFactory;
+    
+    static interface Renderer {
+        String getExtension();
+        String getContentType();
+        void render(List<EvaluationResult> results, Writer output) throws IOException;
+    }
+    
+    private final Renderer [] renderers = { new JsonResultRendererImpl(), new HtmlResultRendererImpl() };
+    
+    @Activate
+    public void activate(ComponentContext ctx) {
+        consolePlugin = new SlingHealthCheckWebconsolePlugin(ctx.getBundleContext(), resourceResolverFactory, this);
+    }
+    
+    @Deactivate
+    public void deactivate(ComponentContext ctx) {
+        consolePlugin.deactivate();
+        consolePlugin = null;
+    }
     
     @Override
     protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) 
-            throws ServletException,IOException {
-        
-        // TODO we could cache the engine + rules, not sure if it's worth it...
+            throws ServletException, IOException {
+        executeRules(request.getResource(), getRuleTagsFromRequest(request), request.getRequestPathInfo().getExtension(), response);
+    }
+    
+    void executeRules(Resource rulesRoot, String [] tags, String extension, HttpServletResponse response) 
+            throws ServletException, IOException {
         final RulesEngine engine = healthcheck.getNewRulesEngine();
-        engine.addRules(parser.parseResource(request.getResource()));
-        response.setContentType("application/json");
+        engine.addRules(parser.parseResource(rulesRoot));
+        final TaggedRuleFilter filter = new TaggedRuleFilter(tags);
+        
+        Renderer renderer = null;
+        for(Renderer x : renderers) {
+            if(extension.equals(x.getExtension())) {
+                renderer = x;
+                break;
+            }
+        }
+        if(renderer == null) {
+            throw new ServletException("No Renderer found for extension " + extension);
+        }
+        
+        log.info("Executing rules found under {} with {} and rendering with {}", 
+                new Object[] { rulesRoot.getPath(), filter, renderer });
+        response.setContentType(renderer.getContentType());
         response.setCharacterEncoding("UTF-8");
-        final TaggedRuleFilter filter = new TaggedRuleFilter(getRuleTagsFromRequest(request));
-        log.info("Executing rules found under {} with {}", request.getResource().getPath(), filter);
         renderer.render(engine.evaluateRules(filter), response.getWriter());
         response.getWriter().flush();
     }

Added: sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/SlingHealthCheckWebconsolePlugin.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/SlingHealthCheckWebconsolePlugin.java?rev=1489927&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/SlingHealthCheckWebconsolePlugin.java (added)
+++ sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/SlingHealthCheckWebconsolePlugin.java Wed Jun  5 15:44:32 2013
@@ -0,0 +1,165 @@
+/*
+ * 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.sling.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** Webconsole plugin to execute health check rules */ 
+@SuppressWarnings("serial")
+public class SlingHealthCheckWebconsolePlugin extends HttpServlet {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+    private final SlingHealthCheckServlet servlet;
+    private final ServiceRegistration service;
+    private final ResourceResolverFactory resourceResolverFactory;  
+    public static final String TITLE = "Sling Health Check";
+    public static final String LABEL = "healthcheck";
+    public static final String PARAM_PATH = "rulesPath";
+    public static final String PARAM_TAGS = "tags";
+    
+    SlingHealthCheckWebconsolePlugin(BundleContext ctx, ResourceResolverFactory rrf, SlingHealthCheckServlet s){
+        servlet = s;
+        resourceResolverFactory = rrf;
+        
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+        props.put(Constants.SERVICE_DESCRIPTION, "Sling Health Check Web Console Plugin");
+        props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
+        props.put(Constants.SERVICE_PID, getClass().getName());
+        props.put("felix.webconsole.label", LABEL);
+        props.put("felix.webconsole.title", TITLE);
+        props.put("felix.webconsole.css", "/" + LABEL + "/res/ui/healthcheck.css");
+
+        service = ctx.registerService(new String[] { "javax.servlet.Servlet" }, this, props);
+        log.info("{} registered as a Webconsole plugin", this);
+    }
+    
+    public void deactivate() {
+        log.info("Unregistering {}", this);
+        service.unregister();
+    }
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        // Static resource?
+        final String pathInfo = req.getPathInfo();
+        if(pathInfo!= null && pathInfo.contains("res/ui")) {
+            final String prefix = "/" + LABEL;
+            final InputStream is = getClass().getResourceAsStream(pathInfo.substring(prefix.length()));
+            if(is == null) {
+                resp.sendError(HttpServletResponse.SC_NOT_FOUND, pathInfo);
+            }
+            final byte [] buffer = new byte[16384];
+            int n=0;
+            while( (n = is.read(buffer, 0, buffer.length)) > 0) {
+                resp.getOutputStream().write(buffer, 0, n); 
+            }
+            resp.getOutputStream().flush();
+            return;
+        }
+        
+        // Send parameters form
+        doForm(req, resp);
+        
+        // And execute rules if we got a path
+        final String path = getParam(req, PARAM_PATH, null);
+        final String [] tags = getParam(req, PARAM_TAGS, "").split(",");
+        
+        if(path == null || path.trim().length() == 0) {
+            return;
+        }
+        
+        ResourceResolver resolver = null;
+        try {
+            resolver = resourceResolverFactory.getAdministrativeResourceResolver(null);
+            final Resource r = resolver.getResource(path);
+            if(r == null) {
+                resp.sendError(HttpServletResponse.SC_NOT_FOUND, path);
+            }
+            servlet.executeRules(r, tags, "html", resp);
+        } catch (LoginException e) {
+            throw new ServletException("Unable to get a ResourceResolver", e);
+        } finally {
+            if(resolver != null) {
+                resolver.close();
+            }
+        }
+    }
+    
+    private void doForm(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        final PrintWriter pw = resp.getWriter();
+        final WebConsoleHelper c = new WebConsoleHelper(pw);
+        pw.print("<form method='get'>");
+        pw.println("<table class='content' cellpadding='0' cellspacing='0' width='100%'>");
+        c.titleHtml(TITLE, "To execute health check rules, enter the path of a rules definition "
+                + "( or the root of a subtree of definitions) "
+                + " and an optional list of tags if you want to select a tagged subset of the rules.");
+        
+        final String path = getParam(req, PARAM_PATH, "");
+        
+        c.tr(); 
+        c.tdLabel("Rules definition path");
+        c.tdContent();
+        pw.println("<input type='text' name='" + PARAM_PATH + "' value='" + path + "' class='input' size='80'>");
+        c.closeTd(); 
+        c.closeTr();
+        
+        final String tags = getParam(req, PARAM_TAGS, "");
+        
+        c.tr(); 
+        c.tdLabel("Rule tags (comma-separated)");
+        c.tdContent();
+        pw.println("<input type='text' name='" + PARAM_TAGS + "' value='" + tags + "' class='input' size='80'>");
+        c.closeTd(); 
+        c.closeTr();
+        
+        c.tr(); 
+        c.tdContent();
+        pw.println("<input type='submit' value='Execute selected rules'/>");
+        c.closeTd(); 
+        c.closeTr();
+        
+        pw.println("</table></form>");
+    }
+
+    private String getParam(HttpServletRequest req, String name, String defaultValue) {
+        String result = req.getParameter(name);
+        if(result == null) {
+            result = defaultValue;
+        }
+        return result;
+    }
+}

Propchange: sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/SlingHealthCheckWebconsolePlugin.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/SlingHealthCheckWebconsolePlugin.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/WebConsoleHelper.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/WebConsoleHelper.java?rev=1489927&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/WebConsoleHelper.java (added)
+++ sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/WebConsoleHelper.java Wed Jun  5 15:44:32 2013
@@ -0,0 +1,68 @@
+/*
+ * 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.sling.impl;
+
+import java.io.PrintWriter;
+
+import org.apache.sling.api.request.ResponseUtil;
+
+/** Webconsole plugin to execute health check rules */ 
+class WebConsoleHelper {
+    
+    final PrintWriter pw;
+    
+    WebConsoleHelper(PrintWriter w) {
+        pw = w;
+    }
+
+    PrintWriter writer() {
+        return pw;
+    }
+    
+    void tdContent() {
+        pw.print("<td class='content' colspan='2'>");
+    }
+
+    void closeTd() {
+        pw.print("</td>");
+    }
+
+    void closeTr() {
+        pw.println("</tr>");
+    }
+
+    void tdLabel(final String label) {
+        pw.println("<td class='content'>" + ResponseUtil.escapeXml(label) + "</td>");
+    }
+
+    void tr() {
+        pw.println("<tr class='content'>");
+    }
+
+    void titleHtml(String title, String description) {
+        tr();
+        pw.println("<th colspan='3' class='content container'>" + ResponseUtil.escapeXml(title) + "</th>");
+        closeTr();
+
+        if (description != null) {
+            tr();
+            pw.println("<td colspan='3' class='content'>" +ResponseUtil.escapeXml(description) + "</th>");
+            closeTr();
+        }
+    }
+}

Propchange: sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/WebConsoleHelper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/java/org/apache/sling/hc/sling/impl/WebConsoleHelper.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/resources/res/ui/healthcheck.css
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/resources/res/ui/healthcheck.css?rev=1489927&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/resources/res/ui/healthcheck.css (added)
+++ sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/resources/res/ui/healthcheck.css Wed Jun  5 15:44:32 2013
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.healthcheck .logDEBUG {
+    color:grey;
+}
+
+.healthcheck .logINFO {
+    color:blue;
+}
+
+.healthcheck .logWARN {
+    color:red;
+}
+
+.healthcheck .logERROR {
+    color:red;
+    font-weight:bold;
+}
+
+.healthcheck .nothingToReport {
+	color:green;
+    font-weight:bold;
+}

Propchange: sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/resources/res/ui/healthcheck.css
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/contrib/extensions/healthcheck/hc-sling/src/main/resources/res/ui/healthcheck.css
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Modified: sling/trunk/contrib/extensions/healthcheck/hc-sling/src/test/java/org/apache/sling/hc/sling/MockResolver.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/hc-sling/src/test/java/org/apache/sling/hc/sling/MockResolver.java?rev=1489927&r1=1489926&r2=1489927&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/healthcheck/hc-sling/src/test/java/org/apache/sling/hc/sling/MockResolver.java (original)
+++ sling/trunk/contrib/extensions/healthcheck/hc-sling/src/test/java/org/apache/sling/hc/sling/MockResolver.java Wed Jun  5 15:44:32 2013
@@ -26,6 +26,8 @@ import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.servlet.http.HttpServletRequest;
 
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.PersistenceException;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.mockito.Matchers;
@@ -122,4 +124,81 @@ class MockResolver implements ResourceRe
     public Resource resolve(String arg0) {
         return null;
     }
+
+    @Override
+    public ResourceResolver clone(Map<String, Object> arg0)
+            throws LoginException {
+        return null;
+    }
+
+    @Override
+    public void close() {
+    }
+
+    @Override
+    public void commit() throws PersistenceException {
+    }
+
+    @Override
+    public Resource create(Resource arg0, String arg1, Map<String, Object> arg2)
+            throws PersistenceException {
+        return null;
+    }
+
+    @Override
+    public void delete(Resource arg0) throws PersistenceException {
+    }
+
+    @Override
+    public Object getAttribute(String arg0) {
+        return null;
+    }
+
+    @Override
+    public Iterator<String> getAttributeNames() {
+        return null;
+    }
+
+    @Override
+    public Iterable<Resource> getChildren(Resource arg0) {
+        return null;
+    }
+
+    @Override
+    public String getParentResourceType(Resource arg0) {
+        return null;
+    }
+
+    @Override
+    public String getParentResourceType(String arg0) {
+        return null;
+    }
+
+    @Override
+    public String getUserID() {
+        return null;
+    }
+
+    @Override
+    public boolean hasChanges() {
+        return false;
+    }
+
+    @Override
+    public boolean isLive() {
+        return false;
+    }
+
+    @Override
+    public boolean isResourceType(Resource arg0, String arg1) {
+        return false;
+    }
+
+    @Override
+    public void refresh() {
+    }
+
+    @Override
+    public void revert() {
+    }
 }

Modified: sling/trunk/contrib/extensions/healthcheck/hc-sling/src/test/java/org/apache/sling/hc/sling/MockResource.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/hc-sling/src/test/java/org/apache/sling/hc/sling/MockResource.java?rev=1489927&r1=1489926&r2=1489927&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/healthcheck/hc-sling/src/test/java/org/apache/sling/hc/sling/MockResource.java (original)
+++ sling/trunk/contrib/extensions/healthcheck/hc-sling/src/test/java/org/apache/sling/hc/sling/MockResource.java Wed Jun  5 15:44:32 2013
@@ -1,6 +1,7 @@
 package org.apache.sling.hc.sling;
 
 import java.util.HashMap;
+import java.util.Iterator;
 
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceMetadata;
@@ -104,4 +105,34 @@ class MockResource implements Resource {
     public String getResourceType() {
         return null;
     }
+
+    @Override
+    public Resource getChild(String arg0) {
+        return null;
+    }
+
+    @Override
+    public Iterable<Resource> getChildren() {
+        return null;
+    }
+
+    @Override
+    public String getName() {
+        return null;
+    }
+
+    @Override
+    public Resource getParent() {
+        return null;
+    }
+
+    @Override
+    public boolean isResourceType(String arg0) {
+        return false;
+    }
+
+    @Override
+    public Iterator<Resource> listChildren() {
+        return null;
+    }
 }

Modified: sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/RepositoryPresentTest.json
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/RepositoryPresentTest.json?rev=1489927&r1=1489926&r2=1489927&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/RepositoryPresentTest.json (original)
+++ sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/RepositoryPresentTest.json Wed Jun  5 15:44:32 2013
@@ -3,5 +3,6 @@
   "ruleName": "junit",
   "namespace": "sling",
   "jcr:primaryType": "nt:unstructured",
-  "qualifier": "org.apache.sling.hc.demo.tests.RepositoryPresentTest"
+  "qualifier": "org.apache.sling.hc.demo.tests.RepositoryPresentTest",
+  "tags" : [ "junit" ]
 }

Modified: sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/ResourcesExistTest-checkAppsExist.json
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/ResourcesExistTest-checkAppsExist.json?rev=1489927&r1=1489926&r2=1489927&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/ResourcesExistTest-checkAppsExist.json (original)
+++ sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/ResourcesExistTest-checkAppsExist.json Wed Jun  5 15:44:32 2013
@@ -3,5 +3,6 @@
   "ruleName": "junit",
   "namespace": "sling",
   "jcr:primaryType": "nt:unstructured",
-  "qualifier": "org.apache.sling.hc.demo.tests.ResourcesExistTest#checkAppsExist"
+  "qualifier": "org.apache.sling.hc.demo.tests.ResourcesExistTest#checkAppsExist",
+  "tags" : [ "junit" ]
 }

Modified: sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/ResourcesExistTest.json
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/ResourcesExistTest.json?rev=1489927&r1=1489926&r2=1489927&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/ResourcesExistTest.json (original)
+++ sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/ResourcesExistTest.json Wed Jun  5 15:44:32 2013
@@ -3,5 +3,6 @@
   "ruleName": "junit",
   "namespace": "sling",
   "jcr:primaryType": "nt:unstructured",
-  "qualifier": "org.apache.sling.hc.demo.tests.ResourcesExistTest"
+  "qualifier": "org.apache.sling.hc.demo.tests.ResourcesExistTest",
+  "tags" : [ "junit" ]
 }

Modified: sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/junit-sling-all.json
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/junit-sling-all.json?rev=1489927&r1=1489926&r2=1489927&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/junit-sling-all.json (original)
+++ sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/junit-sling-all.json Wed Jun  5 15:44:32 2013
@@ -3,5 +3,6 @@
   "ruleName": "junit",
   "namespace": "sling",
   "jcr:primaryType": "nt:unstructured",
-  "qualifier": "org.apache.sling.hc.demo.tests"
+  "qualifier": "org.apache.sling.hc.demo.tests",
+  "tags" : [ "junit" ]
 }

Modified: sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/script-that-fails.jsp
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/script-that-fails.jsp?rev=1489927&r1=1489926&r2=1489927&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/script-that-fails.jsp (original)
+++ sling/trunk/contrib/extensions/healthcheck/sling-demo/src/main/resources/SLING-CONTENT/apps/hc/demo/script-that-fails.jsp Wed Jun  5 15:44:32 2013
@@ -1,4 +1,3 @@
 # example script that fails as a health check rule
-Anything that the script outputs
-that is not TEST_PASSED, and empty line or a comment
-causes it to fail.
+This script outputs more than just TEST_PASSED
+so the corresponding rule will fail.