Open pdolezal opened 4 years ago
Hi,
i don't reproduce this problem. When the bundle is installed, then i can found this bundle with getBundle( String)
and with getBundles()
and search on array ...
give us a code to reproduce.
Regards Torsten
I extracted some code to reproduce the issue, or actually a part of it. There is probably yet something else in my original code that contributed to the described difference between getBundles
and getBundle
and I'll have to investigate it more thoroughly to isolate it.
However, the code sample below shows a part of the problem, which might be the root cause for the described difference: the framework forgets which bundles were installed in the previous run and therefore allows repeated installations of the same bundle, so that the storage area grows with each run.
package org.example.bug;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.stream.Stream;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.launch.Framework;
import org.osgi.framework.launch.FrameworkFactory;
public final class Main {
public static void main(String... args) throws Exception {
final String location = args[0];
final FrameworkFactory factory = ServiceLoader.load(FrameworkFactory.class).iterator().next();
final Map<String, String> properties = Collections.singletonMap(Constants.FRAMEWORK_STORAGE, "./storage");
final Framework framework = factory.newFramework(properties);
framework.init();
final BundleContext systemBundle = framework.getBundleContext();
if ((systemBundle.getBundle(location) == null)) {
System.out.println("Installing: " + location);
try (InputStream is = Files.newInputStream(Paths.get(location))) {
final Bundle bundle = systemBundle.installBundle(location, is);
System.out.println("Installed: " + bundle);
}
}
Stream.of(systemBundle.getBundles()).forEach(bundle -> System.out.format("%d: %s%n", bundle.getBundleId(), bundle));
framework.stop();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>bug</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<java.version>1.8</java.version>
<java.compiler.source>${java.version}</java.compiler.source>
<java.compiler.target>${java.version}</java.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>osgi.core</artifactId>
<version>5.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.concierge</groupId>
<artifactId>org.eclipse.concierge</artifactId>
<version>5.1.0</version>
<scope>runtime</scope>
</dependency>
<!--
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.framework</artifactId>
<version>6.0.3</version>
<scope>runtime</scope>
</dependency>
-->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.compiler.source}</source>
<target>${java.compiler.target}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Execute several times mvn exec:java -Dexec.mainClass=org.example.bug.Main -Dexec.args=some-bundle.jar
(where some-bundle.jar
points to an actual bundle). IMHO, the more appropriate behavior shows Felix (just swap the framework implementation in the POM as hinted) which does not install the bundle again.
I wonder if it is by design and the storage area should be then cleared for Concierge always to prevent growing it.
Ok ... i think understand the problem. you want an installed bundle to persist across the life cycle of the framework. when concierge started, concierge don't know which bundles existed on last run. And every new start from framework without clean storage added a new storage folder for the install bundle. persistent data don't store on temporary storage, better the bundle define a persistent storage location outside from the storage.
to implement this functionaly please implement a own startup.
When I tried Concierge with own launcher I found out that
BundleContext.getBundle(String)
does not work correctly when the framework uses an existing storage.Basically the scenario follows this pseudocode:
The
bundle
variable is alwaysnull
, while it should return the installed bundle when the code is run second time with the same storage. I tried replacinggetBundle
with something like:And this always works. So the framework apparently knows which bundles were installed, it just does not update its structures for
getBundle
to work properly.The described behavior of
getBundle
in this use case results in duplicated installation of the bundle – and what is even more interesting: the newly installed bundle has the same location as the existing bundle. I believe this is wrong as well and the location should be unique. Maybe the framework implementation fails to check the location duplicity for the same reason.