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

jsedding pushed a commit to branch resolver-2.x-backports
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-servlets-resolver.git

commit d3092c909fa69d06e6b4b9ca02818125211050b7
Author: Carsten Ziegeler <[email protected]>
AuthorDate: Sat Mar 29 17:32:49 2025 +0100

    SLING-12599 : Make dependency to Apache Felix HC optional
    
    (cherry picked from commit 6d6309b797fe1741cc1f7bd23cbdf6b5ab06d2e9)
---
 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;
-    }
 }

Reply via email to