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

joerghoh pushed a commit to branch SLING-12417
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-servlets-resolver.git

commit 8c4b260133a7e977caadc92b427daa6958c2344d
Author: Joerg Hoh <[email protected]>
AuthorDate: Thu Nov 7 16:30:58 2024 +0100

    SLING-12417 add healthcheck
---
 pom.xml                                            |  6 ++
 .../internal/bundle/BundledScriptTracker.java      | 67 +++++++++++++++++++++-
 .../internal/bundle/BundledScriptTrackerTest.java  | 38 ++++++------
 .../resolver/it/ServletResolverTestSupport.java    |  6 ++
 4 files changed, 95 insertions(+), 22 deletions(-)

diff --git a/pom.xml b/pom.xml
index 31a313e..f2d17ee 100644
--- a/pom.xml
+++ b/pom.xml
@@ -279,6 +279,12 @@
             <artifactId>osgi.cmpn</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.healthcheck.api</artifactId>
+            <version>2.0.4</version>
+            <scope>provided</scope>
+        </dependency>
         <!-- Testing -->
         <dependency>
             <groupId>org.apache.sling</groupId>
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 70bb82b..0753ca5 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,6 +52,9 @@ import javax.servlet.http.HttpServletResponse;
 
 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;
@@ -85,6 +88,9 @@ 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;
@@ -93,12 +99,13 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Component(
-        service = {}
+        service = {HealthCheck.class}
 )
 @Capability(namespace = ExtenderNamespace.EXTENDER_NAMESPACE,
             name = BundledScriptTracker.NS_SLING_SCRIPTING_EXTENDER,
             version = "1.0.0")
-public class BundledScriptTracker implements 
BundleTrackerCustomizer<List<ServiceRegistration<Servlet>>> {
+@Designate(ocd=BundledScriptTracker.BundledScriptTrackerConfig.class)
+public class BundledScriptTracker implements 
BundleTrackerCustomizer<List<ServiceRegistration<Servlet>>>, HealthCheck {
     static final String NS_SLING_SCRIPTING_EXTENDER = "sling.scripting";
 
     private static final Logger LOGGER = 
LoggerFactory.getLogger(BundledScriptTracker.class);
@@ -120,14 +127,25 @@ public class BundledScriptTracker implements 
BundleTrackerCustomizer<List<Servic
     private final AtomicReference<Map<Set<String>, 
ServiceRegistration<Servlet>>> dispatchers = new AtomicReference<>();
 
     private volatile List<String> searchPaths;
+    
+    private Set<String> registeredBundles = new HashSet<>();
+    private Set<String> expectedBundles = new HashSet<>();
+    
+    private ServiceRegistration<HealthCheck> healthCheckRegistration = null;
 
     @Activate
-    protected void activate(BundleContext context) {
+    protected void activate(BundleContext context, BundledScriptTrackerConfig 
config) {
         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()));
+            healthCheckRegistration = registerHealthCheck(config.tags());
+            LOGGER.info("Healthcheck configured with mandatory bundles {} for 
tags {}", 
+                    Arrays.toString(config.mandatoryBundles()), 
Arrays.toString(config.tags()));
+        }
     }
 
     @Deactivate
@@ -136,10 +154,23 @@ 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, "Sightly BundledScriptTracker Healthceck");
+        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;
@@ -188,6 +219,7 @@ public class BundledScriptTracker implements 
BundleTrackerCustomizer<List<Servic
                 refreshDispatcher(serviceRegistrations);
                 long duration = Duration.between(registerStart, 
Instant.now()).toMillis();
                 LOGGER.info("Took {}ms to register {} servlets from bundle 
{}.", duration, serviceRegistrations.size(), bundle.getSymbolicName());
+                registeredBundles.add(bundle.getSymbolicName());
                 return serviceRegistrations;
             } else {
                 return Collections.emptyList();
@@ -557,6 +589,23 @@ public class BundledScriptTracker implements 
BundleTrackerCustomizer<List<Servic
         LOGGER.debug("Bundle {} removed", bundle.getSymbolicName());
         regs.forEach(ServiceRegistration::unregister);
         refreshDispatcher(Collections.emptyList());
+        registeredBundles.remove(bundle.getSymbolicName());
+    }
+    
+    @Override
+    public Result execute() {
+        
+        if (expectedBundles == null) {
+            return new Result(Result.Status.OK,"Healthcheck not configured");
+        }
+        
+        if (registeredBundles.containsAll(expectedBundles)) {
+            return new Result(Result.Status.OK,"all expected bundles 
registered");
+        } else {
+            FormattingResultLog log = new FormattingResultLog();
+            log.warn("Expected bundles : {}, present bundles: {}", 
expectedBundles, registeredBundles);
+            return new Result(log);
+        }
     }
 
     private class DispatcherServlet extends GenericServlet {
@@ -756,4 +805,16 @@ public class BundledScriptTracker implements 
BundleTrackerCustomizer<List<Servic
         newSet.addAll(originalCapabilities);
         return newSet;
     }
+
+
+    @ObjectClassDefinition
+    public @interface BundledScriptTrackerConfig {
+        
+        @AttributeDefinition(name="Mandatory Bundles", description="for all of 
the provided symbolic bundle names the "
+                + "registration process must have been completed successfully 
for the healthcheck to report ok")
+        String[] mandatoryBundles();
+        
+        @AttributeDefinition(name="healthcheck tags", description="the tags 
under which the healthcheck should be registered")
+        String[] 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/BundledScriptTrackerTest.java
index 13e19c8..47f7329 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
@@ -1,21 +1,21 @@
-/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ~ 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.
- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+/*
+ * 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 static org.mockito.Mockito.mock;
@@ -37,7 +37,7 @@ public class BundledScriptTrackerTest {
     @Test
     public void removedBundle() {
         BundledScriptTracker tracker = new BundledScriptTracker();
-        tracker.activate(mock(BundleContext.class));
+        
tracker.activate(mock(BundleContext.class),mock(BundledScriptTracker.BundledScriptTrackerConfig.class));
         List<ServiceRegistration<Servlet>> registrations = new ArrayList<>();
         @SuppressWarnings("unchecked")
         ServiceRegistration<Servlet> registration = 
mock(ServiceRegistration.class);
diff --git 
a/src/test/java/org/apache/sling/servlets/resolver/it/ServletResolverTestSupport.java
 
b/src/test/java/org/apache/sling/servlets/resolver/it/ServletResolverTestSupport.java
index 939198e..8919f44 100644
--- 
a/src/test/java/org/apache/sling/servlets/resolver/it/ServletResolverTestSupport.java
+++ 
b/src/test/java/org/apache/sling/servlets/resolver/it/ServletResolverTestSupport.java
@@ -124,6 +124,9 @@ public class ServletResolverTestSupport extends TestSupport 
{
                 //
                 
mavenBundle().groupId("commons-codec").artifactId("commons-codec").version("1.15"),
                 //
+                
mavenBundle().groupId("org.apache.sling").artifactId("org.apache.sling.hc.api").version("1.0.4"),
+                
mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.healthcheck.api").versionAsInProject(),
+                //
                 junitBundles(),
                 newConfiguration("org.apache.felix.http")
                     .put("org.osgi.service.http.port", httpPort)
@@ -137,6 +140,9 @@ public class ServletResolverTestSupport extends TestSupport 
{
                 ),
                 
newConfiguration("org.apache.sling.jcr.base.internal.LoginAdminWhitelist")
                     .put("whitelist.bundles.regexp", "^PAXEXAM.*$")
+                    .asOption(),
+                
newConfiguration("org.apache.sling.servlets.resolver.internal.bundle.BundledScriptTracker")
+                    .put("mandatoryBundles", "testBundle")
                     .asOption()
             )
         );

Reply via email to