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

stefanegli pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-discovery-standalone.git


The following commit(s) were added to refs/heads/master by this push:
     new 38ab13b  SLING-12870 -Introduce offline mode to discovery-standalone 
(#1)
38ab13b is described below

commit 38ab13bd72de1dd48eb41308e871ac21e1a6d90b
Author: ionutzpi <[email protected]>
AuthorDate: Wed Aug 6 14:03:58 2025 +0300

    SLING-12870 -Introduce offline mode to discovery-standalone (#1)
---
 .../sling/discovery/impl/standalone/Config.java    | 38 +++++++++++++
 .../impl/standalone/NoClusterDiscoveryService.java | 27 ++++++++-
 .../standalone/NoClusterDiscoveryServiceTest.java  | 64 +++++++++++++++++++++-
 3 files changed, 125 insertions(+), 4 deletions(-)

diff --git 
a/src/main/java/org/apache/sling/discovery/impl/standalone/Config.java 
b/src/main/java/org/apache/sling/discovery/impl/standalone/Config.java
new file mode 100644
index 0000000..2cafdac
--- /dev/null
+++ b/src/main/java/org/apache/sling/discovery/impl/standalone/Config.java
@@ -0,0 +1,38 @@
+/*
+ * 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.discovery.impl.standalone;
+
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+
+/**
+ * Configuration interface for the standalone discovery service.
+ */
+@ObjectClassDefinition(
+    name = "Apache Sling Discovery Standalone Configuration",
+    description = "Configuration for the standalone discovery service 
implementation"
+)
+public @interface Config {
+
+    @AttributeDefinition(
+        name = "Always Offline",
+        description = "When enabled, it will never report a valid topology and 
no TOPOLOGY_INIT events will be sent to TopologyEventListeners."
+    )
+    boolean always_offline() default false;
+}
diff --git 
a/src/main/java/org/apache/sling/discovery/impl/standalone/NoClusterDiscoveryService.java
 
b/src/main/java/org/apache/sling/discovery/impl/standalone/NoClusterDiscoveryService.java
index a028a00..ef9ac19 100644
--- 
a/src/main/java/org/apache/sling/discovery/impl/standalone/NoClusterDiscoveryService.java
+++ 
b/src/main/java/org/apache/sling/discovery/impl/standalone/NoClusterDiscoveryService.java
@@ -36,6 +36,7 @@ import org.apache.sling.settings.SlingSettingsService;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.metatype.annotations.Designate;
 import org.osgi.service.component.annotations.Reference;
 import org.osgi.service.component.annotations.ReferenceCardinality;
 import org.osgi.service.component.annotations.ReferencePolicy;
@@ -47,6 +48,7 @@ import org.slf4j.LoggerFactory;
  * which can be used for a cluster less installation (= single instance).
  */
 @Component(immediate=true, service = {DiscoveryService.class}) // immediate as 
this is component is also handling the listeners
+@Designate(ocd = Config.class)
 public class NoClusterDiscoveryService implements DiscoveryService {
 
     /** The logger. */
@@ -57,6 +59,11 @@ public class NoClusterDiscoveryService implements 
DiscoveryService {
      */
     private final SlingSettingsService settingsService;
 
+    /**
+     * Configuration flag to always report as offline.
+     */
+    private volatile boolean alwaysOffline = false;
+
     /**
      * All topology event listeners.
      */
@@ -84,9 +91,13 @@ public class NoClusterDiscoveryService implements 
DiscoveryService {
      * Create a new description.
      */
     @Activate
-    public NoClusterDiscoveryService(@Reference final SlingSettingsService 
slingSettingsService) {
+    public NoClusterDiscoveryService(@Reference final SlingSettingsService 
slingSettingsService, final Config config) {
         logger.debug("NoClusterDiscoveryService started.");
         this.settingsService = slingSettingsService;
+        this.alwaysOffline = config.always_offline();
+        if (this.alwaysOffline) {
+            logger.info("Discovery service configured to always report as 
offline");
+        }
         this.createNewView(Type.TOPOLOGY_INIT, false);
     }
 
@@ -118,10 +129,17 @@ public class NoClusterDiscoveryService implements 
DiscoveryService {
             final InstanceDescription myInstanceDescription = new 
InstanceDescriptionImpl(this.settingsService.getSlingId(),
                     this.cachedProperties);
             this.currentTopologyView = new 
TopologyViewImpl(myInstanceDescription);
+            
+            // If always offline is enabled, mark the topology as not current
+            if (this.alwaysOffline) {
+                this.currentTopologyView.invalidate();
+            }
+            
             registeredServices = this.listeners;
             newView = this.currentTopologyView;
 
-            if ( inform ) {
+            // Only inform listeners if not in always offline mode
+            if ( inform && !this.alwaysOffline ) {
                 for(final TopologyEventListener da: registeredServices) {
                     da.handleTopologyEvent(new TopologyEvent(eventType, 
oldView, newView));
                 }
@@ -205,7 +223,10 @@ public class NoClusterDiscoveryService implements 
DiscoveryService {
             currentList.add(listener);
             this.listeners = currentList.toArray(new 
TopologyEventListener[currentList.size()]);
         }
-        listener.handleTopologyEvent(new TopologyEvent(Type.TOPOLOGY_INIT, 
null, this.currentTopologyView));
+        // Only send TOPOLOGY_INIT event if not in always offline mode
+        if (!this.alwaysOffline) {
+            listener.handleTopologyEvent(new TopologyEvent(Type.TOPOLOGY_INIT, 
null, this.currentTopologyView));
+        }
     }
 
     @SuppressWarnings("unused")
diff --git 
a/src/test/java/org/apache/sling/discovery/impl/standalone/NoClusterDiscoveryServiceTest.java
 
b/src/test/java/org/apache/sling/discovery/impl/standalone/NoClusterDiscoveryServiceTest.java
index 8c54e91..404032a 100644
--- 
a/src/test/java/org/apache/sling/discovery/impl/standalone/NoClusterDiscoveryServiceTest.java
+++ 
b/src/test/java/org/apache/sling/discovery/impl/standalone/NoClusterDiscoveryServiceTest.java
@@ -58,6 +58,10 @@ public class NoClusterDiscoveryServiceTest {
     }
 
     private DiscoveryService createService() {
+        return createService(false);
+    }
+
+    private DiscoveryService createService(boolean alwaysOffline) {
         final DiscoveryService service = new NoClusterDiscoveryService(new 
SlingSettingsService() {
 
             @Override
@@ -84,11 +88,25 @@ public class NoClusterDiscoveryServiceTest {
             public String getAbsolutePathWithinSlingHome(String relativePath) {
                 return null;
             }
-        });
+        }, createMockConfig(alwaysOffline));
 
         return service;
     }
 
+    private Config createMockConfig(final boolean alwaysOffline) {
+        return new Config() {
+            @Override
+            public boolean always_offline() {
+                return alwaysOffline;
+            }
+
+            @Override
+            public Class<? extends java.lang.annotation.Annotation> 
annotationType() {
+                return Config.class;
+            }
+        };
+    }
+
     @Test public void testBasics() throws Exception {
         final DiscoveryService service = this.createService();
 
@@ -100,6 +118,33 @@ public class NoClusterDiscoveryServiceTest {
         assertNull(service.getTopology());
     }
 
+    @Test public void testAlwaysOffline() throws Exception {
+        final DiscoveryService service = this.createService(true);
+
+        assertNotNull(service.getTopology());
+        // When always offline is true, the topology should not be current
+        assertFalse(service.getTopology().isCurrent());
+        // The instance should still be a leader (as per Discovery API)
+        assertTrue(service.getTopology().getLocalInstance().isLeader());
+
+        invoke(service, "deactivate");
+
+        assertNull(service.getTopology());
+    }
+
+    @Test public void testAlwaysOnline() throws Exception {
+        final DiscoveryService service = this.createService(false);
+
+        assertNotNull(service.getTopology());
+        assertTrue(service.getTopology().isCurrent());
+        // When always offline is false, the instance should be a leader
+        assertTrue(service.getTopology().getLocalInstance().isLeader());
+
+        invoke(service, "deactivate");
+
+        assertNull(service.getTopology());
+    }
+
     @Test public void testListener() throws Exception {
         final DiscoveryService service = this.createService();
 
@@ -119,6 +164,23 @@ public class NoClusterDiscoveryServiceTest {
         assertNull(events.get(0).getOldView());
     }
 
+    @Test public void testListenerAlwaysOffline() throws Exception {
+        final DiscoveryService service = this.createService(true);
+
+        final List<TopologyEvent> events = new ArrayList<TopologyEvent>();
+
+        final TopologyEventListener listener = new TopologyEventListener() {
+
+            @Override
+            public void handleTopologyEvent(final TopologyEvent event) {
+                events.add(event);
+            }
+        };
+        invoke(service, "bindTopologyEventListener", new Class[] 
{TopologyEventListener.class}, new Object[] {listener});
+        // When always offline is true, no events should be sent
+        assertEquals(0, events.size());
+    }
+
     @Test public void testPropertyChanges() throws Exception {
         final DiscoveryService service = this.createService();
 

Reply via email to