Skip to content

Commit

Permalink
Do not use PackageAdmin for refresh bundles
Browse files Browse the repository at this point in the history
Currently there are two ways to refresh packages, one using the
deprecated PackageAdmin and one using the FrameworkWiring.

This do the following:
- always use FrameworkWiring
- use collections over arrays
- remove some redundant checks and copy of collections
  • Loading branch information
laeubi committed Jan 2, 2024
1 parent dc136d3 commit 28eabc9
Showing 1 changed file with 22 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.net.*;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
import org.eclipse.equinox.internal.simpleconfigurator.utils.*;
import org.osgi.framework.*;
import org.osgi.framework.namespace.*;
Expand Down Expand Up @@ -91,7 +92,7 @@ void install(URL url, boolean exclusiveMode) throws IOException {
}

Set<Bundle> prevouslyResolved = getResolvedBundles();
Collection<Bundle> toRefresh = new ArrayList<>();
Collection<Bundle> toRefresh = new LinkedHashSet<>();
Collection<Bundle> toStart = new ArrayList<>();
if (exclusiveMode) {
toRefresh.addAll(installBundles(expectedState, toStart));
Expand All @@ -109,24 +110,28 @@ void install(URL url, boolean exclusiveMode) throws IOException {
} else {
// In this case the platform is up, we should try to do an incremental resolve
// TODO consider removing this case because it can cause inconsistent results.
refreshPackages(toRefresh.toArray(new Bundle[toRefresh.size()]), manipulatingContext);
if (toRefresh.size() > 0) {
Bundle[] additionalRefresh = getAdditionalRefresh(prevouslyResolved, toRefresh);
if (additionalRefresh.length > 0)
refreshPackages(additionalRefresh, manipulatingContext);
Map<String, List<Bundle>> bundlesByBsn = Arrays.stream(manipulatingContext.getBundles())
.filter(bundle -> bundle.getSymbolicName() != null)
.collect(Collectors.groupingBy(Bundle::getSymbolicName));
// Prior to Luna the Equinox framework would refresh all bundles with the same
// BSN automatically. This is no longer the case for Luna or other framework
// implementations. Here we want to make sure all existing bundles with the
// same BSN are refreshed also.
Set<Bundle> allSameBSNs = new LinkedHashSet<>(); // maintain order and avoid duplicates
for (Bundle bundle : toRefresh) {
allSameBSNs.addAll(bundlesByBsn.getOrDefault(bundle.getSymbolicName(), List.of(bundle)));
}
refreshPackages(allSameBSNs);
refreshPackages(getAdditionalRefresh(prevouslyResolved, toRefresh));
}
}

}

startBundles(toStart.toArray(new Bundle[toStart.size()]));
}

private Bundle[] getAdditionalRefresh(Set<Bundle> previouslyResolved, Collection<Bundle> toRefresh) {
private Collection<Bundle> getAdditionalRefresh(Set<Bundle> previouslyResolved, Collection<Bundle> toRefresh) {
// This is the luna equinox framework or a non-equinox framework.
// Use standard OSGi API.
final Set<Bundle> additionalRefresh = new HashSet<>();
final Set<Bundle> originalRefresh = new HashSet<>(toRefresh);
for (Bundle bundle : toRefresh) {
BundleRevision revision = bundle.adapt(BundleRevision.class);
if (bundle.getState() == Bundle.INSTALLED && revision != null && (revision.getTypes() & BundleRevision.TYPE_FRAGMENT) != 0) {
Expand All @@ -147,7 +152,7 @@ private Bundle[] getAdditionalRefresh(Set<Bundle> previouslyResolved, Collection
if (foundPayLoadReq) {
Collection<BundleCapability> candidates = frameworkWiring.findProviders(hostReq);
for (BundleCapability candidate : candidates) {
if (!originalRefresh.contains(candidate.getRevision().getBundle())) {
if (!toRefresh.contains(candidate.getRevision().getBundle())) {
additionalRefresh.add(candidate.getRevision().getBundle());
}
}
Expand Down Expand Up @@ -201,7 +206,7 @@ private Bundle[] getAdditionalRefresh(Set<Bundle> previouslyResolved, Collection
}
}
}
return additionalRefresh.toArray(new Bundle[additionalRefresh.size()]);
return additionalRefresh;
}

private BundleWiring getHostWiring(BundleWiring wiring) {
Expand Down Expand Up @@ -235,19 +240,7 @@ private void refreshAllBundles() {
toRefresh.add(bundle);
}
}

CountDownLatch latch = new CountDownLatch(1);
FrameworkListener listener = event -> {
if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED) {
latch.countDown();
}
};
frameworkWiring.refreshBundles(toRefresh, listener);
try {
latch.await();
} catch (InterruptedException e) {
// ignore
}
refreshPackages(toRefresh);
}

private Set<Bundle> getDoNotRefresh() {
Expand Down Expand Up @@ -435,26 +428,9 @@ private boolean isFragment(Bundle current) {
return (revision != null) && ((revision.getTypes() & BundleRevision.TYPE_FRAGMENT) != 0);
}

private void refreshPackages(Bundle[] bundles, BundleContext context) {
if (bundles.length == 0 || packageAdminService == null)
private void refreshPackages(Collection<Bundle> bundles) {
if (bundles.isEmpty()) {
return;

// Prior to Luna the Equinox framework would refresh all bundles with the same
// BSN automatically. This is no longer the case for Luna or other framework
// implementations. Here we want to make sure all existing bundles with the
// same BSN are refreshed also.
Set<Bundle> allSameBSNs = new LinkedHashSet<>(); // maintain order and avoid duplicates
for (Bundle bundle : bundles) {
allSameBSNs.add(bundle);
String bsn = bundle.getSymbolicName();
if (bsn != null) {
// look for others with same BSN
Bundle[] sameBSNs = packageAdminService.getBundles(bsn, null);
if (sameBSNs != null) {
// likely contains the bundle we just added above but a set is used
allSameBSNs.addAll(Arrays.asList(sameBSNs));
}
}
}

CountDownLatch latch = new CountDownLatch(1);
Expand All @@ -463,21 +439,12 @@ private void refreshPackages(Bundle[] bundles, BundleContext context) {
latch.countDown();
}
};
context.addFrameworkListener(listener);
packageAdminService.refreshPackages(allSameBSNs.toArray(new Bundle[0]));

frameworkWiring.refreshBundles(bundles, listener);
try {
latch.await();
} catch (InterruptedException e) {
// ignore
}

// if (DEBUG) {
// for (int i = 0; i < bundles.length; i++) {
// System.out.println(SimpleConfiguratorUtils.getBundleStateString(bundles[i]));
// }
// }
context.removeFrameworkListener(listener);
}

private void startBundles(Bundle[] bundles) {
Expand Down

0 comments on commit 28eabc9

Please sign in to comment.