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 Apr 24, 2024
1 parent 44abf02 commit 1b21340
Showing 1 changed file with 21 additions and 52 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 java.util.stream.Stream;
import org.eclipse.equinox.internal.simpleconfigurator.utils.*;
import org.eclipse.osgi.report.resolution.ResolutionReport.Entry.Type;
Expand Down Expand Up @@ -105,7 +106,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 @@ -123,12 +124,19 @@ 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));
}
if (deepRefresh) {
// when refreshing large sets of bundles the resolver sometimes take a choice
Expand Down Expand Up @@ -218,11 +226,10 @@ private Collection<Bundle> getUnresolvedRequirementsProvider(Set<Bundle> doNotRe
.distinct().filter(bundle -> !doNotRefresh.contains(bundle)).toList();
}

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 @@ -243,7 +250,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 @@ -297,7 +304,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 @@ -331,19 +338,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 @@ -531,26 +526,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 @@ -559,21 +537,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 1b21340

Please sign in to comment.