Fix exception during startup when kar is not yet loaded (#2753)
Signed-off-by: Jan N. Klug <github@klug.nrw>pull/2842/head
parent
ba4e73ccf4
commit
0c73547046
|
@ -55,6 +55,12 @@
|
|||
<version>${karaf.compile.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.karaf.kar</groupId>
|
||||
<artifactId>org.apache.karaf.kar.core</artifactId>
|
||||
<version>${karaf.compile.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.core.bundles</groupId>
|
||||
<artifactId>org.openhab.core.io.rest</artifactId>
|
||||
|
|
|
@ -16,6 +16,7 @@ import static java.util.function.Predicate.not;
|
|||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
|
@ -33,6 +34,7 @@ import java.util.Properties;
|
|||
import java.util.Set;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -40,6 +42,8 @@ import java.util.stream.Stream;
|
|||
|
||||
import org.apache.karaf.features.Feature;
|
||||
import org.apache.karaf.features.FeaturesService;
|
||||
import org.apache.karaf.kar.KarService;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.OpenHAB;
|
||||
import org.openhab.core.addon.AddonEventFactory;
|
||||
import org.openhab.core.common.NamedThreadFactory;
|
||||
|
@ -101,9 +105,11 @@ public class FeatureInstaller implements ConfigurationListener {
|
|||
|
||||
private final ConfigurationAdmin configurationAdmin;
|
||||
private final FeaturesService featuresService;
|
||||
private final KarService karService;
|
||||
private static EventPublisher eventPublisher;
|
||||
|
||||
private ScheduledExecutorService scheduler;
|
||||
private @Nullable ScheduledFuture<?> installJob;
|
||||
|
||||
private boolean paxCfgUpdated = true; // a flag used to check whether CM has already successfully updated the pax
|
||||
// configuration as this must be waited for before trying to add feature repos
|
||||
|
@ -121,9 +127,10 @@ public class FeatureInstaller implements ConfigurationListener {
|
|||
|
||||
@Activate
|
||||
public FeatureInstaller(final @Reference ConfigurationAdmin configurationAdmin,
|
||||
final @Reference FeaturesService featuresService) {
|
||||
final @Reference FeaturesService featuresService, final @Reference KarService karService) {
|
||||
this.configurationAdmin = configurationAdmin;
|
||||
this.featuresService = featuresService;
|
||||
this.karService = karService;
|
||||
}
|
||||
|
||||
@Reference
|
||||
|
@ -197,10 +204,35 @@ public class FeatureInstaller implements ConfigurationListener {
|
|||
// which we will receive as another call to modified
|
||||
return;
|
||||
}
|
||||
installAddons(config);
|
||||
// if there is an install job running, we cancel it.
|
||||
ScheduledFuture<?> installJob = this.installJob;
|
||||
if (installJob != null) {
|
||||
logger.trace("Configuration changed. Cancelling installation job.");
|
||||
installJob.cancel(false); // do not interrupt running job, this might cause problems
|
||||
this.installJob = null;
|
||||
}
|
||||
installAddons(config); // we don't have to wait even if the job is running, because method is synchronized
|
||||
});
|
||||
}
|
||||
|
||||
private boolean allKarsInstalled() {
|
||||
try {
|
||||
List<String> karRepos = karService.list();
|
||||
Dictionary<String, Object> felixProperties = configurationAdmin
|
||||
.getConfiguration("org.apache.felix.fileinstall~deploy").getProperties();
|
||||
String addonsDirectory = (String) felixProperties.get("felix.fileinstall.dir");
|
||||
if (addonsDirectory != null) {
|
||||
return Files.list(Path.of(addonsDirectory)).map(Path::getFileName).map(Path::toString)
|
||||
.filter(file -> file.endsWith(".kar"))
|
||||
.map(karFileName -> karFileName.substring(0, karFileName.lastIndexOf(".")))
|
||||
.allMatch(karRepos::contains);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
logger.warn("Could not determine addons folder, its content or the list of installed repositories!");
|
||||
return false;
|
||||
}
|
||||
|
||||
private void waitForConfigUpdateEvent() {
|
||||
int counter = 0;
|
||||
// wait up to 5 seconds for the config update event
|
||||
|
@ -332,7 +364,7 @@ public class FeatureInstaller implements ConfigurationListener {
|
|||
}
|
||||
}
|
||||
if (changed) {
|
||||
properties.put(PROPERTY_MVN_REPOS, repoCfg.stream().collect(Collectors.joining(",")));
|
||||
properties.put(PROPERTY_MVN_REPOS, String.join(",", repoCfg));
|
||||
paxCfg.update(properties);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
|
@ -344,6 +376,15 @@ public class FeatureInstaller implements ConfigurationListener {
|
|||
}
|
||||
|
||||
private synchronized void installAddons(final Map<String, Object> config) {
|
||||
if (!allKarsInstalled()) {
|
||||
// some kars are not installed, delay installation for 15s
|
||||
logger.info("Some .kar files are not installed yet. Delaying add-on installation by 15s.");
|
||||
installJob = scheduler.schedule(() -> installAddons(config), 15, TimeUnit.SECONDS);
|
||||
return;
|
||||
}
|
||||
|
||||
installJob = null; // either this is called by the job itself or it is null anyway
|
||||
|
||||
final Set<String> currentAddons = new HashSet<>(); // the currently installed ones
|
||||
final Set<String> targetAddons = new HashSet<>(); // the target we want to have installed afterwards
|
||||
final Set<String> installAddons = new HashSet<>(); // the ones to be installed (the diff)
|
||||
|
|
Loading…
Reference in New Issue