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
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 @@
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 @@
* @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 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.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 @@
* 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 @@
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 @@
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 @@
}
/**
+ * 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 @@
}
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.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 @@
* 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));
+ }
+
+}