You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@unomi.apache.org by sh...@apache.org on 2022/01/28 08:37:33 UTC

[unomi] branch unomi-1.6.x updated: UNOMI-542 : add consistent check to know if bundles are correctly sta… (#381)

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

shuber pushed a commit to branch unomi-1.6.x
in repository https://gitbox.apache.org/repos/asf/unomi.git


The following commit(s) were added to refs/heads/unomi-1.6.x by this push:
     new 0f9320f  UNOMI-542 : add consistent check to know if bundles are correctly sta… (#381)
0f9320f is described below

commit 0f9320fd9c05cd37852dc8cadae821302ed1b897
Author: jsinovassin <58...@users.noreply.github.com>
AuthorDate: Fri Jan 28 09:35:33 2022 +0100

    UNOMI-542 : add consistent check to know if bundles are correctly sta… (#381)
    
    * UNOMI-542 : add consistent check to know if bundles are correctly started
    
    * handle feddback
    
    (cherry picked from commit d8749bea228c2b586c5c28b91bdd25be90905544)
---
 .../org/apache/unomi/lifecycle/BundleWatcher.java  | 119 ++++++++++++++++-----
 .../resources/OSGI-INF/blueprint/blueprint.xml     |  38 ++++++-
 .../main/resources/org.apache.unomi.lifecycle.cfg  |  19 ++++
 3 files changed, 149 insertions(+), 27 deletions(-)

diff --git a/lifecycle-watcher/src/main/java/org/apache/unomi/lifecycle/BundleWatcher.java b/lifecycle-watcher/src/main/java/org/apache/unomi/lifecycle/BundleWatcher.java
index 828a288..e72b6d7 100644
--- a/lifecycle-watcher/src/main/java/org/apache/unomi/lifecycle/BundleWatcher.java
+++ b/lifecycle-watcher/src/main/java/org/apache/unomi/lifecycle/BundleWatcher.java
@@ -16,7 +16,14 @@
  */
 package org.apache.unomi.lifecycle;
 
-import org.osgi.framework.*;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.SynchronousBundleListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -24,7 +31,17 @@ import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.net.URL;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimerTask;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 /**
  * This class listens to the global Apache Unomi bundle lifecycle, to provide statistics and state of the overall
@@ -35,9 +52,10 @@ public class BundleWatcher implements SynchronousBundleListener, ServiceListener
     private static final Logger logger = LoggerFactory.getLogger(BundleWatcher.class.getName());
 
     private long startupTime;
-    private Map<String,Long> bundleStartupTimes = new LinkedHashMap<>();
-    private long unomiStartedBundleCount = 0;
-    private long requiredStartedBundleCount;
+    private Map<String, Boolean> requiredBundles;
+
+    private ScheduledExecutorService scheduler;
+    private ScheduledFuture<?> scheduledFuture;
 
     private String requiredServices;
     private Set<Filter> requiredServicesFilters = new LinkedHashSet<>();
@@ -48,8 +66,14 @@ public class BundleWatcher implements SynchronousBundleListener, ServiceListener
     private boolean shutdownMessageAlreadyDisplayed = false;
     private List<String> logoLines = new ArrayList<>();
 
-    public void setRequiredStartedBundleCount(long requiredStartedBundleCount) {
-        this.requiredStartedBundleCount = requiredStartedBundleCount;
+    private Integer checkStartupStateRefreshInterval = 60;
+
+    public void setRequiredBundles(Map<String, Boolean> requiredBundles) {
+        this.requiredBundles = requiredBundles;
+    }
+
+    public void setCheckStartupStateRefreshInterval(Integer checkStartupStateRefreshInterval) {
+        this.checkStartupStateRefreshInterval = checkStartupStateRefreshInterval;
     }
 
     public void setRequiredServices(String requiredServices) {
@@ -70,6 +94,7 @@ public class BundleWatcher implements SynchronousBundleListener, ServiceListener
     }
 
     public void init() {
+        scheduler = Executors.newSingleThreadScheduledExecutor();
         bundleContext.addBundleListener(this);
         bundleContext.addServiceListener(this);
         loadLogo();
@@ -78,9 +103,26 @@ public class BundleWatcher implements SynchronousBundleListener, ServiceListener
         logger.info("Bundle watcher initialized.");
     }
 
+    private boolean allBundleStarted() {
+        return getInactiveBundles().isEmpty();
+    }
+
+    private void displayLogsForInactiveBundles() {
+        getInactiveBundles().forEach(inactiveBundle -> logger
+                .warn("The bundle {} is in not active, some errors could happen when using the application", inactiveBundle));
+    }
+
+    private List<String> getInactiveBundles() {
+        return requiredBundles.entrySet().stream().filter(entry -> !entry.getValue()).map(Map.Entry::getKey).collect(Collectors.toList());
+
+    }
+
     public void destroy() {
         bundleContext.removeServiceListener(this);
         bundleContext.removeBundleListener(this);
+        if (scheduledFuture != null) {
+            scheduledFuture.cancel(true);
+        }
         logger.info("Bundle watcher shutdown.");
     }
 
@@ -91,7 +133,7 @@ public class BundleWatcher implements SynchronousBundleListener, ServiceListener
                 break;
             case BundleEvent.STARTED:
                 if (event.getBundle().getSymbolicName().startsWith("org.apache.unomi")) {
-                    unomiStartedBundleCount++;
+                    requiredBundles.put(event.getBundle().getSymbolicName(), true);
                     checkStartupComplete();
                 }
                 break;
@@ -99,9 +141,11 @@ public class BundleWatcher implements SynchronousBundleListener, ServiceListener
                 break;
             case BundleEvent.STOPPED:
                 if (event.getBundle().getSymbolicName().startsWith("org.apache.unomi")) {
-                    unomiStartedBundleCount--;
+                    requiredBundles.put(event.getBundle().getSymbolicName(), false);
                 }
                 break;
+            default:
+                break;
         }
     }
 
@@ -146,16 +190,45 @@ public class BundleWatcher implements SynchronousBundleListener, ServiceListener
         }
     }
 
+    private void displayLogsForInactiveServices() {
+        requiredServicesFilters.forEach(requiredServicesFilters -> {
+            ServiceReference[] serviceReference = new ServiceReference[0];
+            String filterToString = requiredServicesFilters.toString();
+            try {
+                serviceReference = bundleContext.getServiceReferences((String) null, filterToString);
+            } catch (InvalidSyntaxException e) {
+                logger.error("Failed to get the service reference for {}", filterToString, e);
+            }
+            if (serviceReference == null) {
+                logger.warn("No service found for the filter {}, some errors could happen when using the application", filterToString);
+            }
+        });
+    }
+
     private void checkStartupComplete() {
         if (!isStartupComplete()) {
+            if (scheduledFuture == null || scheduledFuture.isCancelled()) {
+                TimerTask task = new TimerTask() {
+                    @Override
+                    public void run() {
+                        displayLogsForInactiveBundles();
+                        displayLogsForInactiveServices();
+                        checkStartupComplete();
+                    }
+                };
+                scheduledFuture = scheduler
+                        .scheduleWithFixedDelay(task, checkStartupStateRefreshInterval, checkStartupStateRefreshInterval, TimeUnit.SECONDS);
+            }
             return;
         }
+        if (scheduledFuture != null) {
+            scheduledFuture.cancel(true);
+            scheduledFuture = null;
+        }
         if (!startupMessageAlreadyDisplayed) {
             long totalStartupTime = System.currentTimeMillis() - startupTime;
-            if (logoLines.size() > 0) {
-                for (String logoLine : logoLines) {
-                    System.out.println(logoLine);
-                }
+            if (!logoLines.isEmpty()) {
+                logoLines.forEach(System.out::println);
             }
             String buildNumber = "n/a";
             if (bundleContext.getBundle().getHeaders().get("Implementation-Build") != null) {
@@ -165,25 +238,23 @@ public class BundleWatcher implements SynchronousBundleListener, ServiceListener
             if (bundleContext.getBundle().getHeaders().get("Implementation-TimeStamp") != null) {
                 timestamp = bundleContext.getBundle().getHeaders().get("Implementation-TimeStamp");
             }
-            String versionMessage = "  " + bundleContext.getBundle().getVersion().toString() + "  Build:" + buildNumber + "  Timestamp:" + timestamp;
+            String versionMessage =
+                    "  " + bundleContext.getBundle().getVersion().toString() + "  Build:" + buildNumber + "  Timestamp:" + timestamp;
             System.out.println(versionMessage);
             System.out.println("--------------------------------------------------------------------------");
-            System.out.println("Successfully started " + unomiStartedBundleCount + " bundles and " + matchedRequiredServicesCount + " required services in " + totalStartupTime + " ms");
-            logger.info("Apache Unomi version: " + versionMessage);
-            logger.info("Apache Unomi successfully started {} bundles and {} required services in {} ms", unomiStartedBundleCount, matchedRequiredServicesCount, totalStartupTime);
+            System.out.println(
+                    "Successfully started " + requiredBundles.size() + " bundles and " + requiredServicesFilters.size() + " " + "required "
+                            + "services in " + totalStartupTime + " ms");
+            logger.info("Apache Unomi version: {}", versionMessage);
+            logger.info("Apache Unomi successfully started {} bundles and {} required services in {} ms", requiredBundles.size(),
+                    requiredServicesFilters.size(), totalStartupTime);
             startupMessageAlreadyDisplayed = true;
             shutdownMessageAlreadyDisplayed = false;
         }
     }
 
     public boolean isStartupComplete() {
-        if (unomiStartedBundleCount < requiredStartedBundleCount) {
-            return false;
-        }
-        if (matchedRequiredServicesCount < requiredServicesFilters.size()) {
-            return false;
-        }
-        return true;
+        return allBundleStarted() && matchedRequiredServicesCount == requiredServicesFilters.size();
     }
 
     private void loadLogo() {
diff --git a/lifecycle-watcher/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/lifecycle-watcher/src/main/resources/OSGI-INF/blueprint/blueprint.xml
index 3fe88cf..bed16c8 100644
--- a/lifecycle-watcher/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ b/lifecycle-watcher/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -25,15 +25,47 @@
     <cm:property-placeholder persistent-id="org.apache.unomi.lifecycle"
                              update-strategy="reload" placeholder-prefix="${lifecycle.">
         <cm:default-properties>
-            <cm:property name="requiredStartedBundleCount" value="16" />
-            <cm:property name="requiredServices" value="(urlPatterns=/eventcollector),(urlPatterns=/context.json)" />
+            <cm:property name="checkStartupState.refresh.interval" value="60"/>
+            <cm:property name="requiredServices" value="(urlPatterns=/eventcollector),(urlPatterns=/context.json),(osgi.service.blueprint.compname=elasticSearchPersistenceServiceImpl)" />
         </cm:default-properties>
     </cm:property-placeholder>
 
     <bean id="bundleWatcher" init-method="init" destroy-method="destroy" class="org.apache.unomi.lifecycle.BundleWatcher">
         <property name="bundleContext" ref="blueprintBundleContext"/>
         <property name="requiredServices" value="${lifecycle.requiredServices}" />
-        <property name="requiredStartedBundleCount" value="${lifecycle.requiredStartedBundleCount}" />
+        <property name="checkStartupStateRefreshInterval" value="${lifecycle.checkStartupState.refresh.interval}"/>
+        <property name="requiredBundles">
+            <map>
+                <entry key="org.apache.unomi.api" value="false"/>
+                <entry key="org.apache.unomi.common" value="false"/>
+                <entry key="org.apache.unomi.scripting" value="false"/>
+                <entry key="org.apache.unomi.metrics" value="false"/>
+                <entry key="org.apache.unomi.persistence-spi" value="false"/>
+                <entry key="org.apache.unomi.persistence-elasticsearch-core" value="false"/>
+                <entry key="org.apache.unomi.services" value="false"/>
+                <entry key="org.apache.unomi.cxs-lists-extension-services" value="false"/>
+                <entry key="org.apache.unomi.cxs-lists-extension-rest" value="false"/>
+                <entry key="org.apache.unomi.cxs-geonames-services" value="false"/>
+                <entry key="org.apache.unomi.cxs-geonames-rest" value="false"/>
+                <entry key="org.apache.unomi.cxs-privacy-extension-services" value="false"/>
+                <entry key="org.apache.unomi.cxs-privacy-extension-rest" value="false"/>
+                <entry key="org.apache.unomi.rest" value="false"/>
+                <entry key="org.apache.unomi.wab" value="false"/>
+                <entry key="org.apache.unomi.plugins-base" value="false"/>
+                <entry key="org.apache.unomi.plugins-request" value="false"/>
+                <entry key="org.apache.unomi.plugins-mail" value="false"/>
+                <entry key="org.apache.unomi.plugins-optimization-test" value="false"/>
+                <entry key="org.apache.unomi.cxs-lists-extension-actions" value="false"/>
+                <entry key="org.apache.unomi.router-api" value="false"/>
+                <entry key="org.apache.unomi.router-core" value="false"/>
+                <entry key="org.apache.unomi.router-service" value="false"/>
+                <entry key="org.apache.unomi.router-rest" value="false"/>
+                <entry key="org.apache.unomi.shell-dev-commands" value="false"/>
+                <entry key="org.apache.unomi.web-tracker-wab" value="false"/>
+                <entry key="org.apache.unomi.groovy-actions-services" value="false"/>
+                <entry key="org.apache.unomi.groovy-actions-rest" value="false"/>
+            </map>
+        </property>
     </bean>
 
     <service id="bundleWatcherService" ref="bundleWatcher">
diff --git a/lifecycle-watcher/src/main/resources/org.apache.unomi.lifecycle.cfg b/lifecycle-watcher/src/main/resources/org.apache.unomi.lifecycle.cfg
new file mode 100644
index 0000000..e2bd0f2
--- /dev/null
+++ b/lifecycle-watcher/src/main/resources/org.apache.unomi.lifecycle.cfg
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+# The interval in seconds to check again the bundles and services state
+checkStartupState.refresh.interval=${org.apache.unomi.lifecycle.checkStartupState.refresh.interval:-60}