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}