SLING-8342 Migration to Felix HC runtime
diff --git a/pom.xml b/pom.xml
index 9de1a67..d14156f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,11 +24,10 @@
     <parent>
         <groupId>org.apache.sling</groupId>
         <artifactId>sling</artifactId>
-        <version>26</version>
+        <version>34</version>
         <relativePath/>
     </parent>
 
-    <groupId>org.apache.sling</groupId>
     <artifactId>org.apache.sling.hc.support</artifactId>
     <packaging>bundle</packaging>
     <version>1.0.5-SNAPSHOT</version>
@@ -50,10 +49,6 @@
         <plugins>
             <plugin>
                 <groupId>org.apache.felix</groupId>
-                <artifactId>maven-scr-plugin</artifactId>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
                 <extensions>true</extensions>
             </plugin>
@@ -61,73 +56,88 @@
     </build>
 
     <dependencies>
+    
         <dependency>
             <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.compendium</artifactId>
+            <artifactId>osgi.core</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>osgi.cmpn</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>osgi.annotation</artifactId>
+            <version>6.0.1</version>
+            <scope>provided</scope>
+        </dependency>    
+    
+        <dependency>
             <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.scr.annotations</artifactId>
+            <artifactId>org.apache.felix.healthcheck.api</artifactId>
+            <version>2.0.0</version>
             <scope>provided</scope>
         </dependency>
-        <dependency>
-            <groupId>org.apache.sling</groupId>
-            <artifactId>org.apache.sling.hc.core</artifactId>
-            <version>1.0.4</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.sling</groupId>
-            <artifactId>org.apache.sling.hc.annotations</artifactId>
-            <version>1.0.4</version>
-        </dependency>
         
         <dependency>
-            <groupId>org.apache.sling</groupId>
-            <artifactId>org.apache.sling.commons.osgi</artifactId>
-            <version>2.2.0</version>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.healthcheck.annotation</artifactId>
+            <version>2.0.0</version>
             <scope>provided</scope>
         </dependency>
+    
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.healthcheck.generalchecks</artifactId>
+            <version>2.0.2</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.4</version>
+            <scope>provided</scope>
+        </dependency>
+                    
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.api</artifactId>
-            <version>2.1.0</version>
+            <version>2.16.2</version>
             <scope>provided</scope>
         </dependency>
+
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.scripting.core</artifactId>
+            <version>2.0.44</version>
+            <scope>provided</scope>
+        </dependency>        
+        
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.jcr.api</artifactId>
             <version>2.0.4</version>
             <scope>provided</scope>
         </dependency>
-        <dependency>
-            <groupId>org.apache.sling</groupId>
-            <artifactId>org.apache.sling.engine</artifactId>
-            <version>2.2.0</version>
-            <scope>provided</scope>
-        </dependency>
+
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
-            <version>1.6.2</version>
         </dependency>
-        <dependency>
-            <groupId>javax.servlet</groupId>
-            <artifactId>servlet-api</artifactId>
-        </dependency>
+
         <dependency>
             <groupId>javax.jcr</groupId>
             <artifactId>jcr</artifactId>
         </dependency>
-         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-simple</artifactId>
-            <version>1.6.2</version>
-            <scope>test</scope>
-        </dependency>
+        
+        <!-- TEST DEPENDENCIES -->
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
+            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.mockito</groupId>
@@ -135,5 +145,13 @@
             <version>1.9.5</version>
             <scope>test</scope>
         </dependency>
+         <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <version>1.6.2</version>
+            <scope>test</scope>
+        </dependency>
+        <!-- END TEST DEPENDENCIES -->
+
      </dependencies>
 </project>
diff --git a/src/main/java/org/apache/sling/hc/support/impl/DefaultLoginsHealthCheck.java b/src/main/java/org/apache/sling/hc/support/impl/DefaultLoginsHealthCheck.java
index 0f1e854..2960f2f 100644
--- a/src/main/java/org/apache/sling/hc/support/impl/DefaultLoginsHealthCheck.java
+++ b/src/main/java/org/apache/sling/hc/support/impl/DefaultLoginsHealthCheck.java
@@ -25,53 +25,46 @@
 import javax.jcr.Session;
 import javax.jcr.SimpleCredentials;
 
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.ConfigurationPolicy;
-import org.apache.felix.scr.annotations.Properties;
-import org.apache.felix.scr.annotations.Property;
-import org.apache.felix.scr.annotations.PropertyUnbounded;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.Service;
-import org.apache.sling.commons.osgi.PropertiesUtil;
-import org.apache.sling.hc.api.HealthCheck;
-import org.apache.sling.hc.api.Result;
-import org.apache.sling.hc.util.FormattingResultLog;
+import org.apache.felix.hc.api.FormattingResultLog;
+import org.apache.felix.hc.api.HealthCheck;
+import org.apache.felix.hc.api.Result;
 import org.apache.sling.jcr.api.SlingRepository;
-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.Reference;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-/** {@link HealthCheck} that checks that Sling default logins fail.
- *  Used to verify that those logins are disabled on production systems */
-@Component(
-        name="org.apache.sling.hc.support.DefaultLoginsHealthCheck",
-        configurationFactory=true,
-        policy=ConfigurationPolicy.REQUIRE,
-        metatype=true,
-        label="Apache Sling Default Logins Health Check",
-        description="Expects default logins to fail, used to verify " +
-                "that they are disabled on production systems")
-@Properties({
-    @Property(name=HealthCheck.NAME,
-            label="Health Check Name", description="Name of this Health Check service."),
-    @Property(name=HealthCheck.TAGS, unbounded=PropertyUnbounded.ARRAY,
-             label="Health Check tags", description="List of tags for this Health Check service, used to select " +
-               "subsets of Health Check services for execution"),
-    @Property(name=HealthCheck.MBEAN_NAME,
-             label="MBean Name", description="Name of the MBean to create for this Health Check.")
-})
-@Service(value=HealthCheck.class)
+/** {@link HealthCheck} that runs an arbitrary script. */
+@Component(service = HealthCheck.class, name = "org.apache.sling.hc.support.DefaultLoginsHealthCheck", configurationPolicy = ConfigurationPolicy.REQUIRE)
+@Designate(ocd = DefaultLoginsHealthCheck.Config.class, factory = true)
 public class DefaultLoginsHealthCheck implements HealthCheck {
 
-    private final Logger log = LoggerFactory.getLogger(getClass());
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultLoginsHealthCheck.class);
 
-    @Property(unbounded=PropertyUnbounded.ARRAY,
-            label="Login credentials",
-            description="Which credentials to check. Each one is in the format \"user:password\" " +
-                "like \"admin:admin\" for example. Do *not* put any confidential passwords here, the goal " +
-                "is just to check that the default/demo logins, which passwords are known anyway, are disabled.")
-    private static final String PROP_LOGINS = "logins";
+    public static final String HC_LABEL = "Health Check: Default Logins";
+
+    @ObjectClassDefinition(name = HC_LABEL, description = "Expects default logins to fail, used to verify that they are disabled on production systems")
+    @interface Config {
+
+        @AttributeDefinition(name = "Name", description = "Name of this health check.")
+        String hc_name() default "Default Logins Check";
+
+        @AttributeDefinition(name = "Tags", description = "List of tags for this health check, used to select subsets of health checks for execution e.g. by a composite health check.")
+        String[] hc_tags() default {};
+
+        @AttributeDefinition(name = "Default Logins", description = "Which credentials to check. Each one is in the format"
+                + " \"user:password\" like \"admin:admin\" for example. Do *not* put any confidential passwords here, the goal "
+                + "is just to check that the default/demo logins, which passwords are known anyway, are disabled.")
+        String[] logins() default "logins";
+
+        @AttributeDefinition
+        String webconsole_configurationFactory_nameHint() default "Default Logins Check: {logins}";
+    }
 
     private List<String> logins;
 
@@ -79,20 +72,20 @@
     private SlingRepository repository;
 
     @Activate
-    public void activate(ComponentContext ctx) {
-        logins = Arrays.asList(PropertiesUtil.toStringArray(ctx.getProperties().get(PROP_LOGINS), new String[] {}));
-        log.info("Activated, logins={}", logins);
+    protected void activate(Config config) {
+        this.logins = Arrays.asList(config.logins());
+        LOG.info("Activated, logins={}", logins);
     }
 
     @Override
     public Result execute() {
-        final FormattingResultLog resultLog = new FormattingResultLog();
-        int checked=0;
-        int failures=0;
+        FormattingResultLog resultLog = new FormattingResultLog();
+        int checked = 0;
+        int failures = 0;
 
-        for(String login : logins) {
-            final String [] parts = login.split(":");
-            if(parts.length != 2) {
+        for (String login : logins) {
+            final String[] parts = login.split(":");
+            if (parts.length != 2) {
                 resultLog.warn("Expected login in the form username:password, got [{}]", login);
                 continue;
             }
@@ -103,28 +96,30 @@
             Session s = null;
             try {
                 s = repository.login(creds);
-                if(s != null) {
+                if (s != null) {
                     failures++;
                     resultLog.warn("Login as [{}] succeeded, was expecting it to fail", username);
                 } else {
                     resultLog.debug("Login as [{}] didn't throw an Exception but returned null Session", username);
                 }
-            } catch(RepositoryException re) {
+            } catch (RepositoryException re) {
                 resultLog.debug("Login as [{}] failed, as expected", username);
             } finally {
-                if(s != null) {
+                if (s != null) {
                     s.logout();
                 }
             }
         }
 
-        if(checked==0) {
+        if (checked == 0) {
             resultLog.warn("Did not check any logins, configured logins={}", logins);
-        } else if(failures != 0){
+        } else if (failures != 0) {
             resultLog.warn("Checked {} logins, {} failures", checked, failures);
         } else {
             resultLog.debug("Checked {} logins, all successful", checked, failures);
         }
+
         return new Result(resultLog);
     }
-}
\ No newline at end of file
+
+}
diff --git a/src/main/java/org/apache/sling/hc/support/impl/InternalRequest.java b/src/main/java/org/apache/sling/hc/support/impl/InternalRequest.java
deleted file mode 100644
index b79fdfe..0000000
--- a/src/main/java/org/apache/sling/hc/support/impl/InternalRequest.java
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * 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.support.impl;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.UnsupportedEncodingException;
-import java.security.Principal;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Vector;
-
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletInputStream;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpSession;
-
-public class InternalRequest implements HttpServletRequest {
-
-    private final String path;
-    private final Map<String, Object> attributes = new HashMap<String, Object>();
-    
-    public InternalRequest(String path) {
-        this.path = path;
-    }
-    
-    @Override
-    public Object getAttribute(String key) {
-        return attributes.get(key);
-    }
-
-    @Override
-    public Enumeration<?> getAttributeNames() {
-        return new Vector<String>(attributes.keySet()).elements();
-    }
-
-    @Override
-    public String getCharacterEncoding() {
-        return "UTF-8";
-    }
-
-    @Override
-    public int getContentLength() {
-        return 0;
-    }
-
-    @Override
-    public String getContentType() {
-        return "text/plain";
-    }
-
-    @Override
-    public ServletInputStream getInputStream() throws IOException {
-        return new ServletInputStream() {
-            @Override
-            public int read() throws IOException {
-                return 0;
-            }
-        };
-    }
-
-    @Override
-    public String getLocalAddr() {
-        return "127.0.0.1";
-    }
-
-    @Override
-    public String getLocalName() {
-        return "localhost";
-    }
-
-    @Override
-    public int getLocalPort() {
-        return 0;
-    }
-
-    @Override
-    public Locale getLocale() {
-        return Locale.getDefault();
-    }
-
-    @Override
-    public Enumeration<?> getLocales() {
-        return new Vector<Locale>().elements();
-    }
-
-    @Override
-    public String getParameter(String arg0) {
-        return null;
-    }
-
-    @Override
-    public Map<?,?> getParameterMap() {
-        return new HashMap<String, Object>();
-    }
-
-    @Override
-    public Enumeration<?> getParameterNames() {
-        return new Vector<String>().elements();
-    }
-
-    @Override
-    public String[] getParameterValues(String arg0) {
-        return null;
-    }
-
-    @Override
-    public String getProtocol() {
-        return "http";
-    }
-
-    @Override
-    public BufferedReader getReader() throws IOException {
-        return new BufferedReader(new StringReader(""));
-    }
-
-    @Override
-    public String getRealPath(String arg0) {
-        return path;
-    }
-
-    @Override
-    public String getRemoteAddr() {
-        return "127.0.0.1";
-    }
-
-    @Override
-    public String getRemoteHost() {
-        return "localhost";
-    }
-
-    @Override
-    public int getRemotePort() {
-        return 1234;
-    }
-
-    @Override
-    public RequestDispatcher getRequestDispatcher(String arg0) {
-        return null;
-    }
-
-    @Override
-    public String getScheme() {
-        return "http";
-    }
-
-    @Override
-    public String getServerName() {
-        return "localhost";
-    }
-
-    @Override
-    public int getServerPort() {
-        return 80;
-    }
-
-    @Override
-    public boolean isSecure() {
-        return false;
-    }
-
-    @Override
-    public void removeAttribute(String arg0) {
-    }
-
-    @Override
-    public void setAttribute(String key, Object value) {
-        attributes.put(key, value);
-    }
-
-    @Override
-    public void setCharacterEncoding(String arg0)
-            throws UnsupportedEncodingException {
-    }
-
-    @Override
-    public String getAuthType() {
-        return null;
-    }
-
-    @Override
-    public String getContextPath() {
-        return "";
-    }
-
-    @Override
-    public Cookie[] getCookies() {
-        return null;
-    }
-
-    @Override
-    public long getDateHeader(String arg0) {
-        return 0;
-    }
-
-    @Override
-    public String getHeader(String arg0) {
-        return null;
-    }
-
-    @Override
-    public Enumeration<?> getHeaderNames() {
-        return new Vector<String>().elements();
-    }
-
-    @Override
-    public Enumeration<?> getHeaders(String arg0) {
-        return new Vector<String>().elements();
-    }
-
-    @Override
-    public int getIntHeader(String arg0) {
-        return 0;
-    }
-
-    @Override
-    public String getMethod() {
-        return "GET";
-    }
-
-    @Override
-    public String getPathInfo() {
-        return path;
-    }
-
-    @Override
-    public String getPathTranslated() {
-        return path;
-    }
-
-    @Override
-    public String getQueryString() {
-        return "";
-    }
-
-    @Override
-    public String getRemoteUser() {
-        return "remoteuser";
-    }
-
-    @Override
-    public String getRequestURI() {
-        return "http://localhost" + path;
-    }
-
-    @Override
-    public StringBuffer getRequestURL() {
-        return new StringBuffer(getRequestURI());
-    }
-
-    @Override
-    public String getRequestedSessionId() {
-        return "";
-    }
-
-    @Override
-    public String getServletPath() {
-        return "";
-    }
-
-    @Override
-    public HttpSession getSession() {
-        return null;
-    }
-
-    @Override
-    public HttpSession getSession(boolean arg0) {
-        return null;
-    }
-
-    @Override
-    public Principal getUserPrincipal() {
-        return null;
-    }
-
-    @Override
-    public boolean isRequestedSessionIdFromCookie() {
-        return false;
-    }
-
-    @Override
-    public boolean isRequestedSessionIdFromURL() {
-        return false;
-    }
-
-    @Override
-    public boolean isRequestedSessionIdFromUrl() {
-        return false;
-    }
-
-    @Override
-    public boolean isRequestedSessionIdValid() {
-        return false;
-    }
-
-    @Override
-    public boolean isUserInRole(String arg0) {
-        return false;
-    }
-}
diff --git a/src/main/java/org/apache/sling/hc/support/impl/InternalResponse.java b/src/main/java/org/apache/sling/hc/support/impl/InternalResponse.java
deleted file mode 100644
index 8752628..0000000
--- a/src/main/java/org/apache/sling/hc/support/impl/InternalResponse.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * 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.support.impl;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.Locale;
-
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletResponse;
-
-public class InternalResponse implements HttpServletResponse {
-
-    private int status = 200;
-    
-    private static class DevNullOutputStream extends ServletOutputStream {
-        @Override
-        public void write(int b) {
-        }
-    }
-    
-    @Override
-    public void flushBuffer() throws IOException {
-    }
-
-    @Override
-    public int getBufferSize() {
-        return 0;
-    }
-
-    @Override
-    public String getCharacterEncoding() {
-        return "UTF-8";
-    }
-
-    @Override
-    public String getContentType() {
-        return "text/plain";
-    }
-
-    @Override
-    public Locale getLocale() {
-        return Locale.getDefault();
-    }
-
-    @Override
-    public ServletOutputStream getOutputStream() throws IOException {
-        return new DevNullOutputStream();
-    }
-
-    @Override
-    public PrintWriter getWriter() throws IOException {
-        return new PrintWriter(new DevNullOutputStream());
-    }
-
-    @Override
-    public boolean isCommitted() {
-        return false;
-    }
-
-    @Override
-    public void reset() {
-    }
-
-    @Override
-    public void resetBuffer() {
-    }
-
-    @Override
-    public void setBufferSize(int arg0) {
-    }
-
-    @Override
-    public void setCharacterEncoding(String arg0) {
-    }
-
-    @Override
-    public void setContentLength(int arg0) {
-    }
-
-    @Override
-    public void setContentType(String arg0) {
-    }
-
-    @Override
-    public void setLocale(Locale arg0) {
-    }
-
-    @Override
-    public void addCookie(Cookie arg0) {
-    }
-
-    @Override
-    public void addDateHeader(String arg0, long arg1) {
-    }
-
-    @Override
-    public void addHeader(String arg0, String arg1) {
-    }
-
-    @Override
-    public void addIntHeader(String arg0, int arg1) {
-    }
-
-    @Override
-    public boolean containsHeader(String arg0) {
-        return false;
-    }
-
-    @Override
-    public String encodeRedirectURL(String url) {
-        return url;
-    }
-
-    @Override
-    public String encodeRedirectUrl(String url) {
-        return url;
-    }
-
-    @Override
-    public String encodeURL(String url) {
-        return url;
-    }
-
-    @Override
-    public String encodeUrl(String url) {
-        return url;
-    }
-
-    @Override
-    public void sendError(int s, String arg1) throws IOException {
-        status = s;
-    }
-
-    @Override
-    public void sendError(int s) throws IOException {
-        status = s;
-    }
-
-    @Override
-    public void sendRedirect(String arg0) throws IOException {
-    }
-
-    @Override
-    public void setDateHeader(String arg0, long arg1) {
-    }
-
-    @Override
-    public void setHeader(String arg0, String arg1) {
-    }
-
-    @Override
-    public void setIntHeader(String arg0, int arg1) {
-    }
-
-    @Override
-    public void setStatus(int s, String arg1) {
-        status = s;
-    }
-
-    @Override
-    public void setStatus(int s) {
-        status = s;
-    }
-    
-    public int getStatus() {
-        return status;
-    }
-}
diff --git a/src/main/java/org/apache/sling/hc/support/impl/ScriptedHealthCheck.java b/src/main/java/org/apache/sling/hc/support/impl/ScriptedHealthCheck.java
new file mode 100644
index 0000000..bc6cbe8
--- /dev/null
+++ b/src/main/java/org/apache/sling/hc/support/impl/ScriptedHealthCheck.java
@@ -0,0 +1,214 @@
+/*
+ * 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.support.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Session;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+import javax.script.ScriptEngineManager;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.felix.hc.api.FormattingResultLog;
+import org.apache.felix.hc.api.HealthCheck;
+import org.apache.felix.hc.api.Result;
+import org.apache.felix.hc.generalchecks.util.ScriptEnginesTracker;
+import org.apache.felix.hc.generalchecks.util.ScriptHelper;
+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.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** {@link HealthCheck} that runs an arbitrary script. */
+@Component(service = HealthCheck.class, name = "org.apache.sling.hc.support.ScriptedHealthCheck", configurationPolicy = ConfigurationPolicy.REQUIRE)
+@Designate(ocd = ScriptedHealthCheck.Config.class, factory = true)
+public class ScriptedHealthCheck implements HealthCheck {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ScriptedHealthCheck.class);
+
+    public static final String HC_LABEL = "Health Check: Sling Script";
+
+    public static final String JCR_FILE_URL_PREFIX = "jcr:";
+    private static final String JCR_CONTENT = "/jcr:content";
+
+    @ObjectClassDefinition(name = HC_LABEL, description = "NOTE: This Sling pendant of org.apache.felix.hc.generalchecks.ScriptedHealthCheck allows to use scriptUrls with prefix 'jcr:' and has the additional bindings 'resourceResolver' and 'session'. "
+            + "Runs an arbitrary script in given scriping language (via javax.script). "
+            + "The script has the following default bindings available: 'log', 'scriptHelper', 'bundleContext', 'resourceResolver' and 'session'. "
+            + "'log' is an instance of org.apache.felix.hc.api.FormattingResultLog and is used to define the result of the HC. "
+            + "'scriptHelper.getService(classObj)' can be used as shortcut to retrieve a service."
+            + "'scriptHelper.getServices(classObj, filter)' used to retrieve multiple services for a class using given filter. "
+            + "For all services retrieved via scriptHelper, unget() is called automatically at the end of the script execution."
+            + "'bundleContext' is available for advanced use cases. The script does not need to return any value, but if it does and it is "
+            + "a org.apache.felix.hc.api.Result, that result and entries in 'log' are combined then).")
+    @interface Config {
+
+        @AttributeDefinition(name = "Name", description = "Name of this health check.")
+        String hc_name() default "Scripted Health Check";
+
+        @AttributeDefinition(name = "Tags", description = "List of tags for this health check, used to select subsets of health checks for execution e.g. by a composite health check.")
+        String[] hc_tags() default {};
+
+        @AttributeDefinition(name = "Language", description = "The language the script is written in. To use e.g. 'groovy', ensure osgi bundle 'groovy-all' is available.")
+        String language() default "groovy";
+
+        @AttributeDefinition(name = "Script", description = "The script itself (either use 'script' or 'scriptUrl').")
+        String script() default "log.info('ok'); log.warn('not so good'); log.critical('bad') // minimal example";
+
+        @AttributeDefinition(name = "Script Url", description = "Url to the script to be used as alternative source (either use 'script' or 'scriptUrl').")
+        String scriptUrl() default "";
+
+        @AttributeDefinition
+        String webconsole_configurationFactory_nameHint() default "Scripted HC: {hc.name} (tags: {hc.tags}) {scriptUrl} language: {language}";
+    }
+
+    private String language;
+    private String script;
+    private String scriptUrl;
+
+    private BundleContext bundleContext;
+
+    @Reference
+    private ScriptEngineManager scriptEngineManager;
+
+    @Reference
+    private ScriptEnginesTracker scriptEnginesTracker;
+
+    private ScriptHelper scriptHelper = new ScriptHelper();
+
+    @Reference
+    private ResourceResolverFactory resourceResolverFactory;
+
+    @Activate
+    protected void activate(BundleContext context, Config config) {
+        this.bundleContext = context;
+        this.language = config.language().toLowerCase();
+        this.script = config.script();
+        this.scriptUrl = config.scriptUrl();
+
+        if (StringUtils.isNotBlank(script) && StringUtils.isNotBlank(scriptUrl)) {
+            LOG.info("Both 'script' and 'scriptUrl' (=()) are configured, ignoring 'scriptUrl'", scriptUrl);
+            scriptUrl = null;
+        }
+
+        LOG.info("Activated Scripted HC " + config.hc_name() + " with "
+                + (StringUtils.isNotBlank(script) ? "script " + script : "script url " + scriptUrl));
+
+    }
+
+    @Override
+    public Result execute() {
+        FormattingResultLog log = new FormattingResultLog();
+
+        ResourceResolver resourceResolver = null;
+        try {
+            resourceResolver = resourceResolverFactory.getServiceResourceResolver(null);
+
+            boolean urlIsUsed = StringUtils.isBlank(script);
+            String scriptToExecute;
+            if (urlIsUsed) {
+                if (scriptUrl.startsWith(JCR_FILE_URL_PREFIX)) {
+                    String jcrPath = StringUtils.substringAfter(scriptUrl, JCR_FILE_URL_PREFIX);
+                    scriptToExecute = getScriptFromRepository(resourceResolver, jcrPath);
+                } else {
+                    scriptToExecute = scriptHelper.getFileContents(scriptUrl);
+                }
+            } else {
+                scriptToExecute = script;
+            }
+
+            log.info("Executing script {} ({} lines)...", (urlIsUsed ? scriptUrl : " as configured"), scriptToExecute.split("\n").length);
+
+            try {
+                ScriptEngine scriptEngine = getScriptEngine(language);
+
+                Map<String, Object> additionalBindings = new HashMap<String, Object>();
+                additionalBindings.put("resourceResolver", resourceResolver);
+                additionalBindings.put("session", resourceResolver.adaptTo(Session.class));
+                scriptHelper.evalScript(bundleContext, scriptEngine, scriptToExecute, log, additionalBindings, true);
+            } catch (Exception e) {
+                log.healthCheckError("Exception while executing script: " + e, e);
+            }
+
+            return new Result(log);
+        } catch (LoginException e) {
+            throw new IllegalStateException("Could not get resource resolver: " + e, e);
+        } finally {
+            if (resourceResolver != null) {
+                resourceResolver.close();
+            }
+        }
+    }
+
+    private String factoriesToString(List<ScriptEngineFactory> engineFactories) {
+        List<String> factoryArr = new ArrayList<String>();
+        for (ScriptEngineFactory ef : engineFactories) {
+            factoryArr.add(ef.getEngineName() + " (" + StringUtils.join(ef.getExtensions(), ",") + ")");
+        }
+        return StringUtils.join(factoryArr, ", ");
+    }
+
+    private ScriptEngine getScriptEngine(String language) {
+        ScriptEngine scriptEngine = scriptEngineManager.getEngineByExtension(language);
+        if (scriptEngine == null) {
+            try {
+                scriptEngine = scriptHelper.getScriptEngine(scriptEnginesTracker, language);
+            } catch (IllegalArgumentException e) {
+                throw new IllegalStateException("Could not get script engine for " + language + " from available factories: "
+                        + factoriesToString(scriptEngineManager.getEngineFactories()) + ") nor from regular bundles: " + e.getMessage());
+            }
+        }
+        return scriptEngine;
+    }
+
+    private String getScriptFromRepository(ResourceResolver resourceResolver, String jcrPath) {
+        String fileContent;
+        try {
+            Resource dataResource = resourceResolver.getResource(jcrPath + JCR_CONTENT);
+            InputStream is = dataResource.adaptTo(InputStream.class);
+            ByteArrayOutputStream result = new ByteArrayOutputStream();
+            byte[] buffer = new byte[1024];
+            int length;
+            while ((length = is.read(buffer)) != -1) {
+                result.write(buffer, 0, length);
+            }
+            fileContent = result.toString(StandardCharsets.UTF_8.name());
+        } catch (IOException e) {
+            throw new IllegalStateException("Could not load script from path " + jcrPath + ": " + e, e);
+        }
+        return fileContent;
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/hc/support/impl/SlingRequestStatusHealthCheck.java b/src/main/java/org/apache/sling/hc/support/impl/SlingRequestStatusHealthCheck.java
deleted file mode 100644
index 6e33ad3..0000000
--- a/src/main/java/org/apache/sling/hc/support/impl/SlingRequestStatusHealthCheck.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * 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.support.impl;
-
-import java.util.Arrays;
-import java.util.Map;
-
-import javax.servlet.http.HttpServletRequest;
-
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.ConfigurationPolicy;
-import org.apache.felix.scr.annotations.Properties;
-import org.apache.felix.scr.annotations.Property;
-import org.apache.felix.scr.annotations.PropertyUnbounded;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.Service;
-import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.api.resource.ResourceResolverFactory;
-import org.apache.sling.commons.osgi.PropertiesUtil;
-import org.apache.sling.engine.SlingRequestProcessor;
-import org.apache.sling.hc.api.HealthCheck;
-import org.apache.sling.hc.api.Result;
-import org.apache.sling.hc.util.FormattingResultLog;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/** {@link HealthCheck} that checks the HTTP status of Sling requests.
- *  Typically used to check that a freshly installed Sling-based system
- *  is in good shape, contains all required content etc. */
-@Component(
-        name="org.apache.sling.hc.support.SlingRequestStatusHealthCheck",
-        configurationFactory=true,
-        policy=ConfigurationPolicy.REQUIRE,
-        metatype=true,
-        label="Apache Sling Request Status Health Check",
-        description="Checks the HTTP status of Sling requests.")
-@Properties({
-    @Property(name=HealthCheck.NAME,
-            label="Health Check Name", description="Name of this Health Check service."),
-    @Property(name=HealthCheck.TAGS, unbounded=PropertyUnbounded.ARRAY,
-             label="Health Check tags", description="List of tags for this Health Check service, used to select " +
-               "subsets of Health Check services for execution"),
-    @Property(name=HealthCheck.MBEAN_NAME,
-             label="MBean Name", description="Name of the MBean to create for this Health Check.")
-})
-@Service(value=HealthCheck.class)
-public class SlingRequestStatusHealthCheck implements HealthCheck {
-
-    private static final Logger log = LoggerFactory.getLogger(SlingRequestStatusHealthCheck.class);
-    private String [] paths;
-
-    static class PathSpec {
-        int status;
-        String path;
-
-        PathSpec(String configuredPath, FormattingResultLog resultLog) {
-            path = configuredPath;
-            status = 200;
-
-            final String [] parts  = configuredPath.split(":");
-            if(parts.length == 2) {
-                try {
-                    status = Integer.valueOf(parts[1].trim());
-                    path = parts[0].trim();
-                } catch(NumberFormatException nfe) {
-                    resultLog.healthCheckError("NumberFormatException while parsing [{}], invalid status value?", configuredPath);
-                }
-            }
-        }
-    }
-
-    @Property(unbounded=PropertyUnbounded.ARRAY,
-            label="Paths to Check",
-            description="The list of paths to check, optionally with expected HTTP status responses. " +
-                        "An entry like \"/tmp/test.txt:301\", for example, checks that /tmp/test.txt returns a " +
-                        "301 response.")
-    private static final String PROP_PATH = "path";
-
-    @Reference
-    private SlingRequestProcessor requestProcessor;
-
-    @Reference
-    private ResourceResolverFactory resolverFactory;
-
-    @Activate
-    public void activate(final Map<String, Object> properties) {
-        paths = PropertiesUtil.toStringArray(properties.get(PROP_PATH), new String [] {});
-        log.info("Activated, paths={}", Arrays.asList(paths));
-    }
-
-    @Override
-    public Result execute() {
-        final FormattingResultLog resultLog = new FormattingResultLog();
-
-        ResourceResolver resolver = null;
-        int checked = 0;
-        int failed = 0;
-        String lastPath = null;
-
-        try {
-            resolver = resolverFactory.getAdministrativeResourceResolver(null);
-            for(String p : paths) {
-                lastPath = p;
-                final PathSpec ps = new PathSpec(p, resultLog);
-                final HttpServletRequest request = new InternalRequest(ps.path);
-                final InternalResponse response = new InternalResponse();
-                requestProcessor.processRequest(request, response, resolver);
-                final int status = response.getStatus();
-                if(status != ps.status) {
-                    failed++;
-                    resultLog.warn("[{}] returns status {}, expected {}", new Object[] { ps.path, status, ps.status });
-                } else {
-                    resultLog.debug("[{}] returns status {} as expected", ps.path, status);
-                }
-                checked++;
-            }
-        } catch(Exception e) {
-            resultLog.warn("Exception while executing request [{}]: {}", lastPath, e);
-        } finally {
-            if(resolver != null) {
-                resolver.close();
-            }
-        }
-
-        if(checked == 0) {
-            resultLog.warn("No paths checked, empty paths list?");
-        } else {
-            resultLog.info("{} paths checked, {} failures", checked, failed);
-        }
-
-        return new Result(resultLog);
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/hc/support/impl/ThreadUsageHealthCheck.java b/src/main/java/org/apache/sling/hc/support/impl/ThreadUsageHealthCheck.java
deleted file mode 100644
index e08bb92..0000000
--- a/src/main/java/org/apache/sling/hc/support/impl/ThreadUsageHealthCheck.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * 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.support.impl;
-
-import java.lang.management.ManagementFactory;
-import java.lang.management.ThreadInfo;
-import java.lang.management.ThreadMXBean;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.ConfigurationPolicy;
-import org.apache.felix.scr.annotations.Property;
-import org.apache.sling.commons.osgi.PropertiesUtil;
-import org.apache.sling.hc.annotations.SlingHealthCheck;
-import org.apache.sling.hc.api.HealthCheck;
-import org.apache.sling.hc.api.Result;
-import org.apache.sling.hc.util.FormattingResultLog;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Uses ThreadMXBean to show (and potentially WARN about) information about thread usage. Use deadlock detection provided by ThreadMXBean to send CRITICAL. 
- */
-@SlingHealthCheck(name = ThreadUsageHealthCheck.HC_NAME, label = "Apache Sling "
-        + ThreadUsageHealthCheck.HC_NAME, description = "Checks time threads are using ThreadMXBean", tags = { "resources",
-                "threads" }, configurationPolicy = ConfigurationPolicy.REQUIRE)
-public class ThreadUsageHealthCheck implements HealthCheck {
-    private static final Logger LOG = LoggerFactory.getLogger(ThreadUsageHealthCheck.class);
-
-    public static final String HC_NAME = "Thread Usage Health Check";
-
-    private static final long DEFAULT_SAMPLE_PERIOD_IN_MS = 200;
-
-    static final String PROP_SAMPLE_PERIOD_IN_MS = "samplePeriodInMs";
-    @Property(name = PROP_SAMPLE_PERIOD_IN_MS, label = "Sample Period", description = "Period this HC uses to measure", longValue = DEFAULT_SAMPLE_PERIOD_IN_MS)
-    private long samplePeriodInMs;
-
-    static final String PROP_CPU_TIME_THRESHOLD_WARN = "cpuTimeThresholdWarn";
-    @Property(name = PROP_CPU_TIME_THRESHOLD_WARN, label = "CPU Time Threshold for WARN in %", description = "Will WARN once this threshold is reached. Has to be configured according to cores of the system (e.g. use 400% for 4 cores)")
-    private long cpuTimeThresholdWarn;
-    
-    private int availableProcessors;
-    private boolean cpuTimeThresholdWarnIsConfigured;
-
-    @Activate
-    protected final void activate(final Map<String, Object> properties) {
-        this.samplePeriodInMs = PropertiesUtil.toLong(properties.get(PROP_SAMPLE_PERIOD_IN_MS), DEFAULT_SAMPLE_PERIOD_IN_MS);
-
-        this.availableProcessors = Runtime.getRuntime().availableProcessors();
-        long defaultThresholdWarn = availableProcessors * 90; // 100% is rarely reached, 90% means a very busy system
-        this.cpuTimeThresholdWarn = PropertiesUtil.toLong(properties.get(PROP_CPU_TIME_THRESHOLD_WARN), defaultThresholdWarn);
-        this.cpuTimeThresholdWarnIsConfigured = properties.get(PROP_CPU_TIME_THRESHOLD_WARN) !=null;
-
-    }
-
-    @Override
-    public Result execute() {
-        FormattingResultLog log = new FormattingResultLog();
-
-        log.debug("Checking threads for exceeding {}% CPU time within time period of {}ms", cpuTimeThresholdWarn, samplePeriodInMs);
-        
-        try {
-            ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean();
-
-            List<ThreadTimeInfo> threadTimeInfos = collectThreadTimeInfos(log, threadMxBean);
-
-            Collections.sort(threadTimeInfos);
-
-            float totalCpuTimePercentage = 0;
-            for (int i = 0; i < threadTimeInfos.size(); i++) {
-
-                ThreadTimeInfo threadInfo = threadTimeInfos.get(i);
-                float cpuTimePercentage = ((float) threadInfo.getCpuTime() / ((float) samplePeriodInMs * 1000000)) * 100f;
-                totalCpuTimePercentage +=cpuTimePercentage;
-
-                String msg = String.format("%4.1f", cpuTimePercentage) + "% used by thread \"" + threadInfo.name + "\"";
-                if (i<3  || (i<10 && cpuTimePercentage > 15)) {
-                    log.info(msg);
-                } else {
-                    log.debug(msg);
-                }
-            }
-            log.info(threadTimeInfos.size() + " threads using "+String.format("%4.1f", totalCpuTimePercentage)+"% CPU Time");
-            boolean isHighCpuTime = totalCpuTimePercentage > cpuTimeThresholdWarn;
-            if(isHighCpuTime) {
-                log.warn("Threads are consuming significant CPU time "+  ( cpuTimeThresholdWarnIsConfigured ? 
-                        "(more than configured " + cpuTimeThresholdWarn + "% within " + samplePeriodInMs + "ms)" 
-                        : "(more than "+availableProcessors+" cores * 90% = "+cpuTimeThresholdWarn + "%)"));
-            }
-
-            checkForDeadlock(log, threadMxBean);
-
-        } catch (Exception e) {
-            LOG.error("Could not analyse thread usage "+e, e);
-            log.healthCheckError("Could not analyse thread usage", e);
-        }
-      
-        return new Result(log);
-
-    }
-
-    List<ThreadTimeInfo> collectThreadTimeInfos(FormattingResultLog log, ThreadMXBean threadMxBean) {
-        
-        
-        Map<Long, ThreadTimeInfo> threadTimeInfos = new HashMap<Long, ThreadTimeInfo>();
-
-        long[] allThreadIds = threadMxBean.getAllThreadIds();
-        for (long threadId : allThreadIds) {
-            ThreadTimeInfo threadTimeInfo = new ThreadTimeInfo();
-            long threadCpuTimeStart = threadMxBean.getThreadCpuTime(threadId);
-            threadTimeInfo.start = threadCpuTimeStart;
-            ThreadInfo threadInfo = threadMxBean.getThreadInfo(threadId);
-            threadTimeInfo.name = threadInfo!=null?threadInfo.getThreadName():"Thread id "+threadId+" (name not resolvable)";
-            threadTimeInfos.put(threadId, threadTimeInfo);
-        }
-
-        try {
-            Thread.sleep(samplePeriodInMs);
-        } catch (InterruptedException e) {
-            log.warn("Could not sleep configured samplePeriodInMs={} to gather thread load", samplePeriodInMs);
-        }
-
-        for (long threadId : allThreadIds) {
-            ThreadTimeInfo threadTimeInfo = threadTimeInfos.get(threadId);
-            if (threadTimeInfo == null) {
-                continue;
-            }
-            long threadCpuTimeStop = threadMxBean.getThreadCpuTime(threadId);
-            threadTimeInfo.stop = threadCpuTimeStop;
-        }
-        
-        List<ThreadTimeInfo> threads = new ArrayList<ThreadTimeInfo>(threadTimeInfos.values());
-
-        return threads;
-    }
-    
-
-    void checkForDeadlock(FormattingResultLog log, ThreadMXBean threadMxBean) {
-        long[] findDeadlockedThreads = threadMxBean.findDeadlockedThreads();
-        if (findDeadlockedThreads != null) {
-            for (long threadId : findDeadlockedThreads) {
-                log.critical("Thread " + threadMxBean.getThreadInfo(threadId).getThreadName() + " is DEADLOCKED");
-            }
-        }
-    }
-
-    static class ThreadTimeInfo implements Comparable<ThreadTimeInfo> {
-        long start;
-        long stop;
-        String name;
-
-        long getCpuTime() {
-            long cpuTime = stop - start;
-            if(cpuTime < 0) {
-                cpuTime = 0;
-            }
-            return cpuTime;
-        }
-
-        @Override
-        public int compareTo(ThreadTimeInfo otherThreadTimeInfo) {
-            if (otherThreadTimeInfo == null) {
-                return -1;
-            }
-            return (int) (otherThreadTimeInfo.getCpuTime() - this.getCpuTime());
-        }
-
-    }
-
-}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/hc/healthcheck b/src/test/java/org/apache/sling/hc/healthcheck
deleted file mode 100644
index 95de634..0000000
--- a/src/test/java/org/apache/sling/hc/healthcheck
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.impl.healthchecks;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class PathSpecTest {
-    private final String pathSpec;
-    private final String expectedPath;
-    private final int expectedStatus;
-    
-    @Parameters(name="{1}")
-    public static List<Object[]> data() {
-        final List<Object[]> result = new ArrayList<Object[]>();
-
-        result.add(new Object[] { "/one.html", "/one.html", 200 } ); 
-        result.add(new Object[] { "/two.html:404", "/two.html", 404 } ); 
-        result.add(new Object[] { "three.html : 404 ", "three.html", 404 } ); 
-        result.add(new Object[] { "four.html:not an integer", "four.html:not an integer", 200 } ); 
-        result.add(new Object[] { "", "", 200 } ); 
-
-        return result;
-    }
-
-    public PathSpecTest(String pathSpec, String expectedPath, int expectedStatus) {
-        this.pathSpec = pathSpec;
-        this.expectedPath = expectedPath;
-        this.expectedStatus = expectedStatus;
-    }
-    
-    @Test
-    public void testParsing() {
-        final SlingRequestStatusHealthCheck.PathSpec ps = new SlingRequestStatusHealthCheck.PathSpec(pathSpec);
-        assertEquals(expectedPath, ps.path);
-        assertEquals(expectedStatus, ps.status);
-    }
-}
diff --git a/src/test/java/org/apache/sling/hc/healthchecks/SlingRequestStatusHealthCheckTest.java b/src/test/java/org/apache/sling/hc/healthchecks/SlingRequestStatusHealthCheckTest.java
deleted file mode 100644
index 00bba41..0000000
--- a/src/test/java/org/apache/sling/hc/healthchecks/SlingRequestStatusHealthCheckTest.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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.healthchecks;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.api.resource.ResourceResolverFactory;
-import org.apache.sling.engine.SlingRequestProcessor;
-import org.apache.sling.hc.api.Result;
-import org.apache.sling.hc.support.impl.SlingRequestStatusHealthCheck;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-import org.mockito.Matchers;
-import org.mockito.Mockito;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-@RunWith(Parameterized.class)
-public class SlingRequestStatusHealthCheckTest {
-    private SlingRequestStatusHealthCheck hc;
-    private final Result.Status expectedStatus;
-    private final String [] paths;
-    
-    @Parameters(name="{0}")
-    public static List<Object[]> data() {
-            final List<Object[]> result = new ArrayList<Object[]>();
-            result.add(new Object[] { "200.html:200,502.html:1234,436.json:436", Result.Status.WARN });
-            
-            result.add(new Object[] { "", Result.Status.OK }); 
-            result.add(new Object[] { "200.x", Result.Status.OK }); 
-            result.add(new Object[] { "404.html:404", Result.Status.OK }); 
-            result.add(new Object[] { "200.html:200,502.html:502,436.json:436" , Result.Status.OK }); 
-            result.add(new Object[] { "200.html:1234,502.html:502,436.json:436" , Result.Status.WARN }); 
-            result.add(new Object[] { "200.html:200,502.html:1234,436.json:436" , Result.Status.WARN }); 
-            result.add(new Object[] { "200.html:200,502.html:502,436.json:1234" , Result.Status.WARN }); 
-            result.add(new Object[] { "200.html:1234,502.html:1234,436.json:1234" , Result.Status.WARN }); 
-            return result;
-    }
-    
-    @Before
-    public void setup() throws Exception {
-        hc = new SlingRequestStatusHealthCheck();
-        
-        final ResourceResolverFactory rrf = Mockito.mock(ResourceResolverFactory.class);
-        SetField.set(hc, "resolverFactory", rrf);
-        
-        final Answer<Void> a = new Answer<Void> () {
-            @Override
-            public Void answer(InvocationOnMock invocation) {
-                final HttpServletRequest request = (HttpServletRequest)invocation.getArguments()[0];
-                final HttpServletResponse response = (HttpServletResponse)invocation.getArguments()[1];
-                final String path = request.getPathInfo();
-                if(path.length() > 0) {
-                    final String status = path.substring(0, path.indexOf('.'));
-                    response.setStatus(Integer.valueOf(status));
-                }
-                return null;
-            }
-            
-        };
-        
-        final SlingRequestProcessor srp = Mockito.mock(SlingRequestProcessor.class);
-        SetField.set(hc, "requestProcessor", srp);
-        Mockito.doAnswer(a).when(srp).processRequest(
-                Matchers.any(HttpServletRequest.class),  
-                Matchers.any(HttpServletResponse.class), 
-                Matchers.any(ResourceResolver.class));
-        
-        
-        final Map<String, Object> properties = new HashMap<String, Object>();
-        properties.put("path", paths);
-        hc.activate(properties);
-    }
-    
-    public SlingRequestStatusHealthCheckTest(String paths, Result.Status expectedStatus) {
-        this.paths = paths.split(",");
-        this.expectedStatus = expectedStatus;
-        
-    }
-    
-    @Test
-    public void testResult() {
-        assertEquals("Expecting result " + expectedStatus + " for paths=" + paths,
-                expectedStatus, hc.execute().getStatus());
-    }
-}
diff --git a/src/test/java/org/apache/sling/hc/healthchecks/DefaultLoginsHealthCheckTest.java b/src/test/java/org/apache/sling/hc/support/impl/DefaultLoginsHealthCheckTest.java
similarity index 94%
rename from src/test/java/org/apache/sling/hc/healthchecks/DefaultLoginsHealthCheckTest.java
rename to src/test/java/org/apache/sling/hc/support/impl/DefaultLoginsHealthCheckTest.java
index 862b6f8..5b4c382 100644
--- a/src/test/java/org/apache/sling/hc/healthchecks/DefaultLoginsHealthCheckTest.java
+++ b/src/test/java/org/apache/sling/hc/support/impl/DefaultLoginsHealthCheckTest.java
@@ -15,7 +15,7 @@
  * KIND, either express or implied. See the License for the
  * specific language governing permissions and limitations under the License.
  */
-package org.apache.sling.hc.healthchecks;
+package org.apache.sling.hc.support.impl;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -26,8 +26,7 @@
 import javax.jcr.Session;
 import javax.jcr.SimpleCredentials;
 
-import org.apache.sling.hc.api.Result;
-import org.apache.sling.hc.support.impl.DefaultLoginsHealthCheck;
+import org.apache.felix.hc.api.Result;
 import org.apache.sling.jcr.api.SlingRepository;
 import org.junit.Test;
 import org.mockito.Matchers;
diff --git a/src/test/java/org/apache/sling/hc/healthchecks/SetField.java b/src/test/java/org/apache/sling/hc/support/impl/SetField.java
similarity index 95%
rename from src/test/java/org/apache/sling/hc/healthchecks/SetField.java
rename to src/test/java/org/apache/sling/hc/support/impl/SetField.java
index c4577a3..db436c9 100644
--- a/src/test/java/org/apache/sling/hc/healthchecks/SetField.java
+++ b/src/test/java/org/apache/sling/hc/support/impl/SetField.java
@@ -15,7 +15,7 @@
  * KIND, either express or implied. See the License for the
  * specific language governing permissions and limitations under the License.
  */
-package org.apache.sling.hc.healthchecks;
+package org.apache.sling.hc.support.impl;
 
 import java.lang.reflect.Field;
 
diff --git a/src/test/java/org/apache/sling/hc/support/impl/ThreadUsageHealthCheckTest.java b/src/test/java/org/apache/sling/hc/support/impl/ThreadUsageHealthCheckTest.java
deleted file mode 100644
index 257f72b..0000000
--- a/src/test/java/org/apache/sling/hc/support/impl/ThreadUsageHealthCheckTest.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * 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.support.impl;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.MockitoAnnotations.initMocks;
-
-import java.lang.management.ThreadMXBean;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.sling.hc.api.Result;
-import org.apache.sling.hc.support.impl.ThreadUsageHealthCheck.ThreadTimeInfo;
-import org.apache.sling.hc.util.FormattingResultLog;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.Spy;
-
-public class ThreadUsageHealthCheckTest {
-
-    @Spy
-    ThreadUsageHealthCheck threadsHealthCheck;
-
-
-    @Mock
-    Map<String, Object> componentConfig;
-
-    @Before
-    public void setup() {
-        initMocks(this);
-        doNothing().when(threadsHealthCheck).checkForDeadlock(any(FormattingResultLog.class), any(ThreadMXBean.class));
-    }
-
-    @Test
-    public void testThreadActivityWithinThreshold() {
-
-        long samplePeriod = 200L;
-        int processorsAvailable = 4;
-        int busyThreads = 3;
-
-        List<ThreadTimeInfo> resultListOverloaded = getFullLoadThreadInfos(samplePeriod, busyThreads);
-
-        setupExpectations(samplePeriod, processorsAvailable, resultListOverloaded);
-
-        Result result = threadsHealthCheck.execute();
-
-        assertEquals(Result.Status.OK, result.getStatus());
-
-    }
-
-    @Test
-    public void testThreadActivityOverloaded() {
-
-        long samplePeriod = 200L;
-        int processorsAvailable = 4;
-        int busyThreads = 5;
-
-        List<ThreadTimeInfo> resultListOverloaded = getFullLoadThreadInfos(samplePeriod, busyThreads);
-
-        setupExpectations(samplePeriod, processorsAvailable, resultListOverloaded);
-
-        Result result = threadsHealthCheck.execute();
-
-        assertEquals(Result.Status.WARN, result.getStatus());
-
-    }
-
-    private List<ThreadTimeInfo> getFullLoadThreadInfos(long samplePeriod, int count) {
-        List<ThreadTimeInfo> resultList = new ArrayList<ThreadTimeInfo>();
-        for (int i = 0; i < count; i++) {
-            resultList.add(getThreadTimeInfo((long) (samplePeriod * .95)));
-        }
-        return resultList;
-    }
-
-    private void setupExpectations(long samplePeriod, int processorsAvailable, List<ThreadTimeInfo> resultListOk) {
-        doReturn(processorsAvailable * 90).when(componentConfig).get(ThreadUsageHealthCheck.PROP_CPU_TIME_THRESHOLD_WARN);
-        doReturn(samplePeriod).when(componentConfig).get(ThreadUsageHealthCheck.PROP_SAMPLE_PERIOD_IN_MS);
-        threadsHealthCheck.activate(componentConfig);
-        doReturn(resultListOk).when(threadsHealthCheck).collectThreadTimeInfos(any(FormattingResultLog.class), any(ThreadMXBean.class));
-    }
-
-    private ThreadUsageHealthCheck.ThreadTimeInfo getThreadTimeInfo(long diffInMs) {
-        ThreadUsageHealthCheck.ThreadTimeInfo threadTimeInfo = new ThreadUsageHealthCheck.ThreadTimeInfo();
-        threadTimeInfo.start = new Date().getTime();
-        threadTimeInfo.stop = threadTimeInfo.start + (diffInMs * 1000000);
-        threadTimeInfo.name = "Unit Test Thread";
-        return threadTimeInfo;
-    }
-
-}