This is an automated email from the ASF dual-hosted git repository.
cziegeler pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-servlets-resolver.git
The following commit(s) were added to refs/heads/master by this push:
new 6d6309b SLING-12599 : Make dependency to Apache Felix HC optional
6d6309b is described below
commit 6d6309b797fe1741cc1f7bd23cbdf6b5ab06d2e9
Author: Carsten Ziegeler <[email protected]>
AuthorDate: Sat Mar 29 17:32:49 2025 +0100
SLING-12599 : Make dependency to Apache Felix HC optional
---
bnd.bnd | 2 +
.../internal/bundle/BundledScriptTracker.java | 103 ++--------------
.../internal/bundle/BundledScriptTrackerHC.java | 135 +++++++++++++++++++++
...erTest.java => BundledScriptTrackerHCTest.java} | 24 +---
.../internal/bundle/BundledScriptTrackerTest.java | 31 +----
5 files changed, 148 insertions(+), 147 deletions(-)
diff --git a/bnd.bnd b/bnd.bnd
index 3facbe4..275685d 100644
--- a/bnd.bnd
+++ b/bnd.bnd
@@ -1,6 +1,8 @@
Provide-Capability:\
osgi.extender;osgi.extender="org.apache.sling.servlets.resolver";version:Version="1.1"
+Import-Package: org.apache.felix.hc.api;resolution:=optional, *
+
-plugin:\
org.apache.sling.bnd.plugin.headers.parameters.remove.Plugin;\
'Require-Capability'='osgi.service;filter:="(objectClass=org.apache.sling.servlets.resolver.internal.resolution.ResolutionCache)";effective:=active',\
diff --git
a/src/main/java/org/apache/sling/servlets/resolver/internal/bundle/BundledScriptTracker.java
b/src/main/java/org/apache/sling/servlets/resolver/internal/bundle/BundledScriptTracker.java
index cbab0ad..ae08e27 100644
---
a/src/main/java/org/apache/sling/servlets/resolver/internal/bundle/BundledScriptTracker.java
+++
b/src/main/java/org/apache/sling/servlets/resolver/internal/bundle/BundledScriptTracker.java
@@ -52,9 +52,6 @@ import java.util.stream.Stream;
import org.apache.commons.io.FilenameUtils;
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.sling.api.SlingConstants;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
@@ -88,9 +85,6 @@ import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferencePolicy;
-import org.osgi.service.metatype.annotations.AttributeDefinition;
-import org.osgi.service.metatype.annotations.Designate;
-import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.osgi.util.converter.Converter;
import org.osgi.util.converter.Converters;
import org.osgi.util.tracker.BundleTracker;
@@ -98,16 +92,17 @@ import org.osgi.util.tracker.BundleTrackerCustomizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-@Component(service = {HealthCheck.class})
+@Component(immediate = true, service = BundledScriptTracker.class)
+// component needs to be immediate as this is registered as a internal service
+// which is picked up by the optional BundledScriptTrackerHC
@Capability(
namespace = ExtenderNamespace.EXTENDER_NAMESPACE,
name = BundledScriptTracker.NS_SLING_SCRIPTING_EXTENDER,
version = "1.0.0")
-@Designate(ocd = BundledScriptTracker.BundledScriptTrackerConfig.class)
-public class BundledScriptTracker implements
BundleTrackerCustomizer<List<ServiceRegistration<Servlet>>>, HealthCheck {
+public class BundledScriptTracker implements
BundleTrackerCustomizer<List<ServiceRegistration<Servlet>>> {
static final String NS_SLING_SCRIPTING_EXTENDER = "sling.scripting";
- private static final Logger LOGGER =
LoggerFactory.getLogger(BundledScriptTracker.class);
+ static final Logger LOGGER =
LoggerFactory.getLogger(BundledScriptTracker.class);
private static final String REGISTERING_BUNDLE =
"BundledScriptTracker.registering_bundle";
public static final String NS_SLING_SERVLET = "sling.servlet";
public static final String AT_VERSION = "version";
@@ -128,28 +123,14 @@ public class BundledScriptTracker implements
BundleTrackerCustomizer<List<Servic
private volatile List<String> searchPaths;
private Set<String> registeredBundles = new HashSet<>();
- private Set<String> expectedBundles = new HashSet<>();
- private boolean ignoreNonExistingBundles = false;
-
- private ServiceRegistration<HealthCheck> healthCheckRegistration = null;
@Activate
- protected void activate(BundleContext context, BundledScriptTrackerConfig
config) {
+ protected void activate(BundleContext context) {
bundleContext.set(context);
dispatchers.set(new HashMap<>());
BundleTracker<List<ServiceRegistration<Servlet>>> bt = new
BundleTracker<>(context, Bundle.ACTIVE, this);
tracker.set(bt);
bt.open();
- if (config.mandatoryBundles() != null) {
- expectedBundles.addAll(Arrays.asList(config.mandatoryBundles()));
- ignoreNonExistingBundles = config.ignoreNonExistingBundles();
- healthCheckRegistration = registerHealthCheck(config.tags());
- LOGGER.info(
- "Healthcheck configured with mandatory bundles {} for tags
{}, ignoreNonExistingBundles = {}",
- Arrays.toString(config.mandatoryBundles()),
- Arrays.toString(config.tags()),
- ignoreNonExistingBundles);
- }
}
@Deactivate
@@ -158,22 +139,10 @@ public class BundledScriptTracker implements
BundleTrackerCustomizer<List<Servic
if (bt != null) {
bt.close();
}
- if (healthCheckRegistration != null) {
- healthCheckRegistration.unregister();
- healthCheckRegistration = null;
- }
bundleContext.set(null);
dispatchers.set(null);
}
- @SuppressWarnings({"rawtypes", "unchecked"})
- ServiceRegistration<HealthCheck> registerHealthCheck(String[] tags) {
- Dictionary props = new Hashtable();
- props.put(HealthCheck.NAME, "BundledScriptTracker Healthcheck");
- props.put(HealthCheck.TAGS, tags);
- return bundleContext.get().registerService(HealthCheck.class, this,
props);
- }
-
@Reference(policy = ReferencePolicy.DYNAMIC, updated =
"bindSearchPathProvider")
protected void bindSearchPathProvider(final SearchPathProvider
searchPathProvider) {
final boolean reconfiguration = this.searchPaths != null;
@@ -635,42 +604,8 @@ public class BundledScriptTracker implements
BundleTrackerCustomizer<List<Servic
registeredBundles.remove(bundle.getSymbolicName());
}
- @Override
- public Result execute() {
-
- if (expectedBundles == null) {
- return new Result(Result.Status.OK, "Health check is not
configured.");
- }
-
- Set<String> mandatoryAvailableBundles;
- if (ignoreNonExistingBundles) {
- // Filter the provided symbolic names if a bundle with that name
actually exists
- mandatoryAvailableBundles =
filterForExistingBundles(bundleContext.get(), expectedBundles);
- } else {
- mandatoryAvailableBundles = expectedBundles;
- }
-
- if (registeredBundles.containsAll(mandatoryAvailableBundles)) {
- return new Result(Result.Status.OK, "All expected bundles have
registered their scripts.");
- } else {
- FormattingResultLog log = new FormattingResultLog();
- log.warn("Expected bundles : {}, registered bundles: {}",
mandatoryAvailableBundles, registeredBundles);
- return new Result(log);
- }
- }
-
- /**
- * Return the symbolic names of bundles which are provided via {{code
expectedBundles}} and present
- * @param bundleContext a bundleContext
- * @param expectedBundles the symbolic names of bundles to check for
- * @return the symbolic names of present bundles
- */
- protected static Set<String> filterForExistingBundles(BundleContext
bundleContext, Set<String> expectedBundles) {
- List<Bundle> allBundles = Arrays.asList(bundleContext.getBundles());
- return allBundles.stream()
- .map(Bundle::getSymbolicName)
- .filter(s -> expectedBundles.contains(s))
- .collect(Collectors.toSet());
+ public Set<String> getRegisteredBundles() {
+ return Collections.unmodifiableSet(registeredBundles);
}
private class DispatcherServlet extends GenericServlet {
@@ -896,26 +831,4 @@ public class BundledScriptTracker implements
BundleTrackerCustomizer<List<Servic
newSet.addAll(originalCapabilities);
return newSet;
}
-
- @ObjectClassDefinition
- public @interface BundledScriptTrackerConfig {
-
- @AttributeDefinition(
- name = "Mandatory Bundles",
- description =
- "A list of symbolic bundle names for which the "
- + "script registration process must have been
successfully completed for the health check to report ok.")
- String[] mandatoryBundles();
-
- @AttributeDefinition(
- name = "Check for bundle presence",
- description =
- "If disabled, bundles listed as mandatory are ignored
if no bundle with that symbolic name is present")
- boolean ignoreNonExistingBundles() default false;
-
- @AttributeDefinition(
- name = "healthcheck tags",
- description = "the tags under which the healthcheck should be
registered")
- String[] tags() default "systemready";
- }
}
diff --git
a/src/main/java/org/apache/sling/servlets/resolver/internal/bundle/BundledScriptTrackerHC.java
b/src/main/java/org/apache/sling/servlets/resolver/internal/bundle/BundledScriptTrackerHC.java
new file mode 100644
index 0000000..9a7d3a4
--- /dev/null
+++
b/src/main/java/org/apache/sling/servlets/resolver/internal/bundle/BundledScriptTrackerHC.java
@@ -0,0 +1,135 @@
+/*
+ * 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.servlets.resolver.internal.bundle;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.felix.hc.api.FormattingResultLog;
+import org.apache.felix.hc.api.HealthCheck;
+import org.apache.felix.hc.api.Result;
+import org.osgi.framework.Bundle;
+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.Reference;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+
+@Component(
+ property = {
+ "felix.healthcheck.name=BundledScriptTracker",
+ },
+ service = {HealthCheck.class})
+@Designate(ocd = BundledScriptTrackerHC.BundledScriptTrackerHCConfig.class)
+public class BundledScriptTrackerHC implements HealthCheck {
+
+ private final BundledScriptTracker tracker;
+
+ private final BundleContext bundleContext;
+
+ private final Set<String> expectedBundles = new HashSet<>();
+
+ private final boolean ignoreNonExistingBundles;
+
+ @Activate
+ public BundledScriptTrackerHC(
+ final BundleContext context,
+ final @Reference BundledScriptTracker tracker,
+ final BundledScriptTrackerHCConfig config) {
+ this.tracker = tracker;
+ this.bundleContext = context;
+ this.ignoreNonExistingBundles = config.ignoreNonExistingBundles();
+ if (config.mandatoryBundles() != null) {
+ expectedBundles.addAll(Arrays.asList(config.mandatoryBundles()));
+ BundledScriptTracker.LOGGER.info(
+ "Healthcheck configured with mandatory bundles {} for tags
{}, ignoreNonExistingBundles = {}",
+ Arrays.toString(config.mandatoryBundles()),
+ Arrays.toString(config.hc_tags()),
+ ignoreNonExistingBundles);
+ }
+ }
+
+ @Override
+ public Result execute() {
+ if (this.expectedBundles.isEmpty()) {
+ return new Result(Result.Status.OK, "Health check is not
configured.");
+ }
+
+ final Set<String> mandatoryAvailableBundles;
+ if (this.ignoreNonExistingBundles) {
+ // Filter the provided symbolic names if a bundle with that name
actually exists
+ mandatoryAvailableBundles =
filterForExistingBundles(this.bundleContext, this.expectedBundles);
+ } else {
+ mandatoryAvailableBundles = this.expectedBundles;
+ }
+
+ if
(this.tracker.getRegisteredBundles().containsAll(mandatoryAvailableBundles)) {
+ return new Result(Result.Status.OK, "All expected bundles have
registered their scripts.");
+ } else {
+ FormattingResultLog log = new FormattingResultLog();
+ log.warn(
+ "Expected bundles : {}, registered bundles: {}",
+ mandatoryAvailableBundles,
+ this.tracker.getRegisteredBundles());
+ return new Result(log);
+ }
+ }
+
+ /**
+ * Return the symbolic names of bundles which are provided via {{code
expectedBundles}} and present
+ * @param bundleContext a bundleContext
+ * @param expectedBundles the symbolic names of bundles to check for
+ * @return the symbolic names of present bundles
+ */
+ protected static Set<String> filterForExistingBundles(
+ final BundleContext bundleContext, final Set<String>
expectedBundles) {
+ final List<Bundle> allBundles =
Arrays.asList(bundleContext.getBundles());
+ return allBundles.stream()
+ .map(Bundle::getSymbolicName)
+ .filter(s -> expectedBundles.contains(s))
+ .collect(Collectors.toSet());
+ }
+
+ @ObjectClassDefinition
+ public @interface BundledScriptTrackerHCConfig {
+
+ @AttributeDefinition(
+ name = "Mandatory Bundles",
+ description =
+ "A list of symbolic bundle names for which the "
+ + "script registration process must have been
successfully completed for the health check to report ok.")
+ String[] mandatoryBundles();
+
+ @AttributeDefinition(
+ name = "Check for bundle presence",
+ description =
+ "If disabled, bundles listed as mandatory are ignored
if no bundle with that symbolic name is present")
+ boolean ignoreNonExistingBundles() default false;
+
+ @AttributeDefinition(
+ name = "healthcheck tags",
+ description = "the tags under which the healthcheck should be
registered")
+ String[] hc_tags() default "systemready";
+ }
+}
diff --git
a/src/test/java/org/apache/sling/servlets/resolver/internal/bundle/BundledScriptTrackerTest.java
b/src/test/java/org/apache/sling/servlets/resolver/internal/bundle/BundledScriptTrackerHCTest.java
similarity index 66%
copy from
src/test/java/org/apache/sling/servlets/resolver/internal/bundle/BundledScriptTrackerTest.java
copy to
src/test/java/org/apache/sling/servlets/resolver/internal/bundle/BundledScriptTrackerHCTest.java
index 7c9a226..727bdd3 100644
---
a/src/test/java/org/apache/sling/servlets/resolver/internal/bundle/BundledScriptTrackerTest.java
+++
b/src/test/java/org/apache/sling/servlets/resolver/internal/bundle/BundledScriptTrackerHCTest.java
@@ -18,10 +18,6 @@
*/
package org.apache.sling.servlets.resolver.internal.bundle;
-import javax.servlet.Servlet;
-
-import java.util.ArrayList;
-import java.util.List;
import java.util.Set;
import org.junit.Test;
@@ -29,28 +25,12 @@ import org.mockito.Mockito;
import org.mockito.internal.util.collections.Sets;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleEvent;
-import org.osgi.framework.ServiceRegistration;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-public class BundledScriptTrackerTest {
- @Test
- public void removedBundle() {
- BundledScriptTracker tracker = new BundledScriptTracker();
- tracker.activate(mock(BundleContext.class),
mock(BundledScriptTracker.BundledScriptTrackerConfig.class));
- List<ServiceRegistration<Servlet>> registrations = new ArrayList<>();
- @SuppressWarnings("unchecked")
- ServiceRegistration<Servlet> registration =
mock(ServiceRegistration.class);
- registrations.add(registration);
- tracker.removedBundle(mock(Bundle.class), mock(BundleEvent.class),
registrations);
- verify(registration).unregister();
- }
+public class BundledScriptTrackerHCTest {
@Test
public void test_filterForExistingBundles() {
@@ -62,7 +42,7 @@ public class BundledScriptTrackerTest {
.getBundles();
Set<String> expectedSymbolicNames = Sets.newSet("a", "b", "z");
- Set<String> res = BundledScriptTracker.filterForExistingBundles(bc,
expectedSymbolicNames);
+ Set<String> res = BundledScriptTrackerHC.filterForExistingBundles(bc,
expectedSymbolicNames);
assertNotNull(res);
assertEquals(2, res.size());
assertTrue(res.contains("a"));
diff --git
a/src/test/java/org/apache/sling/servlets/resolver/internal/bundle/BundledScriptTrackerTest.java
b/src/test/java/org/apache/sling/servlets/resolver/internal/bundle/BundledScriptTrackerTest.java
index 7c9a226..6e3216c 100644
---
a/src/test/java/org/apache/sling/servlets/resolver/internal/bundle/BundledScriptTrackerTest.java
+++
b/src/test/java/org/apache/sling/servlets/resolver/internal/bundle/BundledScriptTrackerTest.java
@@ -22,19 +22,13 @@ import javax.servlet.Servlet;
import java.util.ArrayList;
import java.util.List;
-import java.util.Set;
import org.junit.Test;
-import org.mockito.Mockito;
-import org.mockito.internal.util.collections.Sets;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.ServiceRegistration;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -43,7 +37,7 @@ public class BundledScriptTrackerTest {
@Test
public void removedBundle() {
BundledScriptTracker tracker = new BundledScriptTracker();
- tracker.activate(mock(BundleContext.class),
mock(BundledScriptTracker.BundledScriptTrackerConfig.class));
+ tracker.activate(mock(BundleContext.class));
List<ServiceRegistration<Servlet>> registrations = new ArrayList<>();
@SuppressWarnings("unchecked")
ServiceRegistration<Servlet> registration =
mock(ServiceRegistration.class);
@@ -51,27 +45,4 @@ public class BundledScriptTrackerTest {
tracker.removedBundle(mock(Bundle.class), mock(BundleEvent.class),
registrations);
verify(registration).unregister();
}
-
- @Test
- public void test_filterForExistingBundles() {
- BundleContext bc = Mockito.mock(BundleContext.class);
- Mockito.doReturn(new Bundle[] {
- mockBundle("a"), mockBundle("b"), mockBundle("c"),
mockBundle("d"), mockBundle("e")
- })
- .when(bc)
- .getBundles();
-
- Set<String> expectedSymbolicNames = Sets.newSet("a", "b", "z");
- Set<String> res = BundledScriptTracker.filterForExistingBundles(bc,
expectedSymbolicNames);
- assertNotNull(res);
- assertEquals(2, res.size());
- assertTrue(res.contains("a"));
- assertTrue(res.contains("b"));
- }
-
- private static Bundle mockBundle(String symbolicName) {
- Bundle b = Mockito.mock(Bundle.class);
- Mockito.when(b.getSymbolicName()).thenReturn(symbolicName);
- return b;
- }
}