You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/10/18 23:20:07 UTC

[sling-org-apache-sling-hc-api] 05/08: SLING-6804 - allow selecting health checks by name

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

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

commit bd44d276971ef72906ccddcc5f0982b2d7e2afff
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Thu May 11 20:05:21 2017 +0000

    SLING-6804 - allow selecting health checks by name
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1794887 13f79535-47bb-0310-9956-ffa450edef68
---
 .../hc/api/execution/HealthCheckExecutor.java      |  24 +++
 .../hc/api/execution/HealthCheckSelector.java      | 105 ++++++++++++++
 .../sling/hc/api/execution/package-info.java       |   2 +-
 .../apache/sling/hc/util/FormattingResultLog.java  |   2 +
 .../apache/sling/hc/util/HealthCheckFilter.java    | 161 ++++++++++++++-------
 .../apache/sling/hc/util/HealthCheckMetadata.java  |   2 +
 .../org/apache/sling/hc/util/package-info.java     |   2 +-
 .../sling/hc/util/HealthCheckFilterTest.java       |  97 +++++++++++++
 8 files changed, 343 insertions(+), 52 deletions(-)

diff --git a/src/main/java/org/apache/sling/hc/api/execution/HealthCheckExecutor.java b/src/main/java/org/apache/sling/hc/api/execution/HealthCheckExecutor.java
index e41858c..4cab49c 100644
--- a/src/main/java/org/apache/sling/hc/api/execution/HealthCheckExecutor.java
+++ b/src/main/java/org/apache/sling/hc/api/execution/HealthCheckExecutor.java
@@ -32,11 +32,33 @@ import org.osgi.annotation.versioning.ProviderType;
 public interface HealthCheckExecutor {
 
     /**
+     * Executes all health checks matching the supplied filter options.
+     * If no options are supplied, all health checks are executed.
+     *
+     * @param selector filter selector
+     * @return List of results. The list might be empty.
+     */
+    List<HealthCheckExecutionResult> execute(HealthCheckSelector selector);
+
+    /**
+     * Executes all health checks with the supplied filter options.
+     * If no options are supplied, all health checks are executed.
+     *
+     * @param selector filter selector
+     * @param options options for controlling execution behavior
+     *
+     * @return List of results. The list might be empty.
+     */
+    List<HealthCheckExecutionResult> execute(HealthCheckSelector selector, HealthCheckExecutionOptions options);
+
+    /**
      * Executes all health checks with the supplied list of tags.
      * If no tags are supplied, all health checks are executed.
      *
      * @return List of results. The list might be empty.
+     * @deprecated use execute(HealthCheckFilter.Options)
      */
+    @Deprecated
     List<HealthCheckExecutionResult> execute(String... tags);
 
     /**
@@ -47,7 +69,9 @@ public interface HealthCheckExecutor {
      * @param tags tags to be executed
      *
      * @return List of results. The list might be empty.
+     * @deprecated use execute(HealthCheckFilter.Options, HealthCheckExecutionOptions)
      */
+    @Deprecated
     List<HealthCheckExecutionResult> execute(HealthCheckExecutionOptions options, String... tags);
 
 }
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/hc/api/execution/HealthCheckSelector.java b/src/main/java/org/apache/sling/hc/api/execution/HealthCheckSelector.java
new file mode 100644
index 0000000..362d817
--- /dev/null
+++ b/src/main/java/org/apache/sling/hc/api/execution/HealthCheckSelector.java
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+package org.apache.sling.hc.api.execution;
+
+import org.apache.sling.hc.api.HealthCheck;
+import org.apache.sling.hc.util.HealthCheckFilter;
+import org.osgi.annotation.versioning.ProviderType;
+
+import java.util.Arrays;
+
+/**
+ * Parameter class to pass a set of tags and names to the filter.
+ */
+@ProviderType
+public final class HealthCheckSelector {
+
+    private String[] tags;
+    private String[] names;
+
+    public String[] tags() {
+        return tags;
+    }
+
+    public String[] names() {
+        return names;
+    }
+
+    private HealthCheckSelector() {}
+
+    /**
+     * Copy the specified names into the current tags array.
+     * @param tags the new tags. Specify null to clear the current tag array
+     * @return this
+     */
+    public HealthCheckSelector withTags(String... tags) {
+        if (this.tags == null) {
+            this.tags = tags;
+        } else if (tags != null) {
+            String[] copy = Arrays.copyOf(this.tags, this.tags.length + tags.length);
+            System.arraycopy(tags, 0, copy, this.tags.length, tags.length);
+            this.tags = copy;
+        } else {
+            this.tags = null;
+        }
+        return this;
+    }
+
+
+    /**
+     * Copy the specified names into the current names array.
+     * @param names the new names. Specify null to clear the current name array
+     * @return this
+     */
+    public HealthCheckSelector withNames(String... names) {
+        if (this.names == null) {
+            this.names = names;
+        } else if (names != null) {
+            String[] copy = Arrays.copyOf(this.names, this.names.length + names.length);
+            System.arraycopy(names, 0, copy, this.names.length, names.length);
+            this.names = copy;
+        } else {
+            this.names = null;
+        }
+        return this;
+    }
+
+
+    public static HealthCheckSelector empty() {
+        return  new HealthCheckSelector();
+    }
+
+    public static HealthCheckSelector tags(String... tags) {
+        HealthCheckSelector selector = new HealthCheckSelector();
+        selector.tags = tags;
+        return selector;
+    }
+
+    public static HealthCheckSelector names(String... names) {
+        HealthCheckSelector selector = new HealthCheckSelector();
+        selector.names = names;
+        return selector;
+    }
+
+    @Override
+    public String toString() {
+        return "HealthCheckSelector{" +
+                "tags=" + tags == null ? "*" : Arrays.toString(tags) +
+                ", names=" + names == null ? "*" : Arrays.toString(names) +
+                '}';
+    }
+}
diff --git a/src/main/java/org/apache/sling/hc/api/execution/package-info.java b/src/main/java/org/apache/sling/hc/api/execution/package-info.java
index dc8b8aa..d34f80e 100644
--- a/src/main/java/org/apache/sling/hc/api/execution/package-info.java
+++ b/src/main/java/org/apache/sling/hc/api/execution/package-info.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-@Version("1.1.0")
+@Version("1.2.0")
 package org.apache.sling.hc.api.execution;
 
 import org.osgi.annotation.versioning.Version;
diff --git a/src/main/java/org/apache/sling/hc/util/FormattingResultLog.java b/src/main/java/org/apache/sling/hc/util/FormattingResultLog.java
index e37dd72..2493722 100644
--- a/src/main/java/org/apache/sling/hc/util/FormattingResultLog.java
+++ b/src/main/java/org/apache/sling/hc/util/FormattingResultLog.java
@@ -22,9 +22,11 @@ import java.util.Locale;
 
 import org.apache.sling.hc.api.Result;
 import org.apache.sling.hc.api.ResultLog;
+import org.osgi.annotation.versioning.ProviderType;
 import org.slf4j.helpers.MessageFormatter;
 
 /** Utility that provides a logging-like facade on a ResultLog */
+@ProviderType
 public class FormattingResultLog extends ResultLog {
     
     private ResultLog.Entry createEntry(Result.Status status, String format, Object ... args) {
diff --git a/src/main/java/org/apache/sling/hc/util/HealthCheckFilter.java b/src/main/java/org/apache/sling/hc/util/HealthCheckFilter.java
index 5466492..c851a66 100644
--- a/src/main/java/org/apache/sling/hc/util/HealthCheckFilter.java
+++ b/src/main/java/org/apache/sling/hc/util/HealthCheckFilter.java
@@ -25,12 +25,17 @@ import java.util.List;
 import java.util.Set;
 
 import org.apache.sling.hc.api.HealthCheck;
+import org.apache.sling.hc.api.execution.HealthCheckSelector;
+import org.osgi.annotation.versioning.ProviderType;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.sling.hc.api.execution.HealthCheckSelector.tags;
+import static org.apache.sling.hc.api.execution.HealthCheckSelector.empty;
+
 /**
  * Select from available {@link HealthCheck} services.
  * Once this filter object and the returned health check services are no longer
@@ -40,6 +45,7 @@ import org.slf4j.LoggerFactory;
  * This class is not thread safe and instances shouldn't be used concurrently
  * from different threads.
  */
+@ProviderType
 public class HealthCheckFilter {
 
     private final Logger log = LoggerFactory.getLogger(getClass());
@@ -57,13 +63,8 @@ public class HealthCheckFilter {
         bundleContext = bc;
     }
 
-    /**
-     * Get all health check services with one of the supplied tags.
-     * @return A list of services - might be the empty list if none matches
-     */
-    @SuppressWarnings("unchecked")
-    public List<HealthCheck> getTaggedHealthChecks(final String... tags) {
-        final ServiceReference [] refs = this.getTaggedHealthCheckServiceReferences(tags);
+    public List<HealthCheck> getHealthChecks(final HealthCheckSelector selector) {
+        final ServiceReference [] refs = this.getHealthCheckServiceReferences(selector);
         final List<HealthCheck> result = new ArrayList<HealthCheck>();
 
         if ( refs != null ) {
@@ -83,52 +84,14 @@ public class HealthCheckFilter {
         return result;
     }
 
-    /**
-     * Get all service references for health check services with one of the supplied tags. Uses logical "and" to combine tags.
-     * @return An array of service references - might be an empty error if none matches
-     */
-    public ServiceReference[] getTaggedHealthCheckServiceReferences(final String... tags) {
-        return getTaggedHealthCheckServiceReferences(false, tags);
+    public ServiceReference[] getHealthCheckServiceReferences(final HealthCheckSelector selector) {
+        return getHealthCheckServiceReferences(selector, false);
     }
 
-    /**
-     * Get all service references for health check services with one of the supplied tags.
-     * 
-     * @param combineWithOr If true will return all health checks that have at least one of the tags set. 
-     *        If false will return only health checks that have all given tags assigned.
-     * @param tags the tags to look for
-     * @return An array of service references - might be an empty error if none matches
-     */
-    public ServiceReference[] getTaggedHealthCheckServiceReferences(boolean combineWithOr, final String... tags) {
-        // Build service filter
-        final StringBuilder filterBuilder = new StringBuilder();
-        filterBuilder.append("(&(objectClass=").append(HealthCheck.class.getName()).append(")");
-        final int prefixLen = OMIT_PREFIX.length();
-        final StringBuilder filterBuilderForOrOperator = new StringBuilder(); // or filters
-        for(String tag : tags) {
-            tag = tag.trim();
-            if(tag.length() == 0) {
-                continue;
-            }
-            if(tag.startsWith(OMIT_PREFIX)) {
-                // ommit tags always have to be added as and-clause
-                filterBuilder.append("(!(").append(HealthCheck.TAGS).append("=").append(tag.substring(prefixLen)).append("))");
-            } else {
-                // add regular tags in the list either to outer and-clause or inner or-clause 
-                if (combineWithOr) {
-                    filterBuilderForOrOperator.append("(").append(HealthCheck.TAGS).append("=").append(tag).append(")");
-                } else {
-                    filterBuilder.append("(").append(HealthCheck.TAGS).append("=").append(tag).append(")");
-                }
-            }
-        }
-        // add "or" clause if we have accumulated any 
-        if (filterBuilderForOrOperator.length() > 0) {
-            filterBuilder.append("(|").append(filterBuilderForOrOperator).append(")");
-        }
-        filterBuilder.append(")");
+    public ServiceReference[] getHealthCheckServiceReferences(final HealthCheckSelector selector, boolean combineTagsWithOr) {
+        final CharSequence filterBuilder = selector != null ? getServiceFilter(selector, combineTagsWithOr) : getServiceFilter(empty(), combineTagsWithOr);
 
-        log.debug("OSGi service filter in getTaggedHealthCheckServiceReferences(): {}", filterBuilder);
+        log.debug("OSGi service filter in getHealthCheckServiceReferences(): {}", filterBuilder);
 
         try {
             final String filterString = filterBuilder.length() == 0 ? null : filterBuilder.toString();
@@ -149,6 +112,42 @@ public class HealthCheckFilter {
     }
 
     /**
+     * Get all health check services with one of the supplied tags.
+     * @return A list of services - might be the empty list if none matches
+     * @deprecated use getHealthChecks() instead
+     */
+    @Deprecated
+    public List<HealthCheck> getTaggedHealthChecks(final String... tags) {
+        final HealthCheckSelector selector = tags(tags);
+        return getHealthChecks(selector);
+    }
+
+    /**
+     * Get all service references for health check services with one of the supplied tags. Uses logical "and" to combine tags.
+     * @return An array of service references - might be an empty error if none matches
+     * @deprecated use getHealthCheckServiceReferences() instead
+     */
+    @Deprecated
+    public ServiceReference[] getTaggedHealthCheckServiceReferences(final String... tags) {
+        return getHealthCheckServiceReferences(tags(tags), false);
+    }
+
+    /**
+     * Get all service references for health check services with one of the supplied tags.
+     * 
+     * @param combineWithOr If true will return all health checks that have at least one of the tags set. 
+     *        If false will return only health checks that have all given tags assigned.
+     * @param tags the tags to look for
+     * @return An array of service references - might be an empty error if none matches
+     * @deprecated use getHealthCheckServiceReferences() instead
+     */
+    @Deprecated
+    public ServiceReference[] getTaggedHealthCheckServiceReferences(boolean combineWithOr, final String... tags) {
+        final HealthCheckSelector selector = tags(tags);
+        return getHealthCheckServiceReferences(selector, combineWithOr);
+    }
+
+    /**
      * Dispose all used service references
      */
     public void dispose() {
@@ -157,4 +156,66 @@ public class HealthCheckFilter {
         }
         this.usedReferences.clear();
     }
+
+    CharSequence getServiceFilter(HealthCheckSelector selector, boolean combineTagsWithOr) {
+        // Build service filter
+        final StringBuilder filterBuilder = new StringBuilder();
+        filterBuilder.append("(&(objectClass=").append(HealthCheck.class.getName()).append(")");
+        final int prefixLen = HealthCheckFilter.OMIT_PREFIX.length();
+        final StringBuilder filterBuilderForOrOperator = new StringBuilder(); // or filters
+        final StringBuilder tagsBuilder = new StringBuilder();
+        int tagsAndClauses = 0;
+        if (selector.tags() != null) {
+            for (String tag : selector.tags()) {
+                tag = tag.trim();
+                if (tag.length() == 0) {
+                    continue;
+                }
+                if (tag.startsWith(HealthCheckFilter.OMIT_PREFIX)) {
+                    // ommit tags always have to be added as and-clause
+                    filterBuilder.append("(!(").append(HealthCheck.TAGS).append("=").append(tag.substring(prefixLen)).append("))");
+                } else {
+                    // add regular tags in the list either to outer and-clause or inner or-clause
+                    if (combineTagsWithOr) {
+                        filterBuilderForOrOperator.append("(").append(HealthCheck.TAGS).append("=").append(tag).append(")");
+                    } else {
+                        tagsBuilder.append("(").append(HealthCheck.TAGS).append("=").append(tag).append(")");
+                        tagsAndClauses++;
+                    }
+                }
+            }
+        }
+        boolean addedNameToOrBuilder = false;
+        if (selector.names() != null) {
+            for (String name : selector.names()) {
+                name = name.trim();
+                if (name.length() == 0) {
+                    continue;
+                }
+                if (name.startsWith(HealthCheckFilter.OMIT_PREFIX)) {
+                    // ommit tags always have to be added as and-clause
+                    filterBuilder.append("(!(").append(HealthCheck.NAME).append("=").append(name.substring(prefixLen)).append("))");
+                } else {
+                    // names are always ORd
+                    filterBuilderForOrOperator.append("(").append(HealthCheck.NAME).append("=").append(name).append(")");
+                    addedNameToOrBuilder = true;
+                }
+            }
+        }
+        if (addedNameToOrBuilder) {
+            if (tagsAndClauses > 1) {
+                filterBuilderForOrOperator.append("(&").append(tagsBuilder).append(")");
+            } else {
+                filterBuilderForOrOperator.append(tagsBuilder);
+            }
+        } else {
+            filterBuilder.append(tagsBuilder);
+        }
+        // add "or" clause if we have accumulated any
+        if (filterBuilderForOrOperator.length() > 0) {
+            filterBuilder.append("(|").append(filterBuilderForOrOperator).append(")");
+        }
+        filterBuilder.append(")");
+        return filterBuilder;
+    }
 }
diff --git a/src/main/java/org/apache/sling/hc/util/HealthCheckMetadata.java b/src/main/java/org/apache/sling/hc/util/HealthCheckMetadata.java
index efc378a..d4a9ed1 100644
--- a/src/main/java/org/apache/sling/hc/util/HealthCheckMetadata.java
+++ b/src/main/java/org/apache/sling/hc/util/HealthCheckMetadata.java
@@ -22,6 +22,7 @@ import java.util.LinkedList;
 import java.util.List;
 
 import org.apache.sling.hc.api.HealthCheck;
+import org.osgi.annotation.versioning.ProviderType;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
 
@@ -29,6 +30,7 @@ import org.osgi.framework.ServiceReference;
  * This class helps retrieving meta data information about a health check service.
  * @since 1.1
  */
+@ProviderType
 public class HealthCheckMetadata {
 
     private final String name;
diff --git a/src/main/java/org/apache/sling/hc/util/package-info.java b/src/main/java/org/apache/sling/hc/util/package-info.java
index 131d715..374c719 100644
--- a/src/main/java/org/apache/sling/hc/util/package-info.java
+++ b/src/main/java/org/apache/sling/hc/util/package-info.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-@Version("1.3.0")
+@Version("1.4.0")
 package org.apache.sling.hc.util;
 
 import org.osgi.annotation.versioning.Version;
diff --git a/src/test/java/org/apache/sling/hc/util/HealthCheckFilterTest.java b/src/test/java/org/apache/sling/hc/util/HealthCheckFilterTest.java
new file mode 100644
index 0000000..44be3ae
--- /dev/null
+++ b/src/test/java/org/apache/sling/hc/util/HealthCheckFilterTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+package org.apache.sling.hc.util;
+
+import org.apache.sling.hc.api.execution.HealthCheckSelector;
+import org.junit.Test;
+import static org.junit.Assert.*;
+import static org.apache.sling.hc.api.execution.HealthCheckSelector.*;
+
+public class HealthCheckFilterTest {
+    
+    private HealthCheckFilter filter = new HealthCheckFilter(null);
+
+    private static void assertStrEquals(String expected, CharSequence actual) {
+        assertEquals(expected, actual.toString());
+    }
+
+    @Test
+    public void testEmptyOptions() {
+        assertStrEquals("(&(objectClass=org.apache.sling.hc.api.HealthCheck))", filter.getServiceFilter(empty(), false));
+    }
+
+    @Test
+    public void testWithOneTag() {
+        HealthCheckSelector selector = tags("foo");
+        assertStrEquals("(&(objectClass=org.apache.sling.hc.api.HealthCheck)(hc.tags=foo))", filter.getServiceFilter(selector, false));
+    }
+
+    @Test
+    public void testWithTwoTags() {
+        HealthCheckSelector selector = tags("foo", "bar");
+        assertStrEquals("(&(objectClass=org.apache.sling.hc.api.HealthCheck)(hc.tags=foo)(hc.tags=bar))", filter.getServiceFilter(selector, false));
+    }
+
+    @Test
+    public void testWithTwoTagsOr() {
+        HealthCheckSelector selector = tags("foo", "bar");
+        assertStrEquals("(&(objectClass=org.apache.sling.hc.api.HealthCheck)(|(hc.tags=foo)(hc.tags=bar)))", filter.getServiceFilter(selector, true));
+    }
+
+    @Test
+    public void testWithTwoTagsExcludeOne() {
+        HealthCheckSelector selector = tags("foo", "bar").withTags("-baz");
+        assertStrEquals("(&(objectClass=org.apache.sling.hc.api.HealthCheck)(!(hc.tags=baz))(hc.tags=foo)(hc.tags=bar))", filter.getServiceFilter(selector, false));
+    }
+
+    @Test
+    public void testWithOneName() {
+        HealthCheckSelector selector = names("foo");
+        assertStrEquals("(&(objectClass=org.apache.sling.hc.api.HealthCheck)(|(hc.name=foo)))", filter.getServiceFilter(selector, false));
+    }
+
+    @Test
+    public void testWithTwoNames() {
+        HealthCheckSelector selector = names("foo").withNames("bar");
+        assertStrEquals("(&(objectClass=org.apache.sling.hc.api.HealthCheck)(|(hc.name=foo)(hc.name=bar)))", filter.getServiceFilter(selector, false));
+    }
+
+    @Test
+    public void testWithTwoNamesExcludingOne() {
+        HealthCheckSelector selector = names("foo", "bar", "-baz");
+        assertStrEquals("(&(objectClass=org.apache.sling.hc.api.HealthCheck)(!(hc.name=baz))(|(hc.name=foo)(hc.name=bar)))", filter.getServiceFilter(selector, false));
+    }
+
+    @Test
+    public void testWithTagAndName() {
+        HealthCheckSelector selector = empty().withTags("t1").withNames("foo");
+        assertStrEquals("(&(objectClass=org.apache.sling.hc.api.HealthCheck)(|(hc.name=foo)(hc.tags=t1)))", filter.getServiceFilter(selector, false));
+    }
+
+    @Test
+    public void testWithTwoOrTagsAndTwoNames() {
+        HealthCheckSelector selector = empty().withNames("foo", "bar").withTags("t1", "t2");
+        assertStrEquals("(&(objectClass=org.apache.sling.hc.api.HealthCheck)(|(hc.tags=t1)(hc.tags=t2)(hc.name=foo)(hc.name=bar)))", filter.getServiceFilter(selector, true));
+    }
+
+    @Test
+    public void testWithTwoAndTagsAndTwoNames() {
+        HealthCheckSelector selector = empty().withNames("foo", "bar").withTags("t1", "t2");
+        assertStrEquals("(&(objectClass=org.apache.sling.hc.api.HealthCheck)(|(hc.name=foo)(hc.name=bar)(&(hc.tags=t1)(hc.tags=t2))))", filter.getServiceFilter(selector, false));
+    }
+
+}

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.