blob: 84e7c03c642f8670f416ef5bbdb49eb8f11fb39f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* René Brandstetter - Bug 419749
* Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
******************************************************************************/
package org.eclipse.e4.ui.internal.workbench;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleEvent;
import org.osgi.util.tracker.BundleTrackerCustomizer;
/**
* A simple {@link BundleTrackerCustomizer} which is able to resolve a bundle by its symbolic name.
*/
/*
* TODO: This implementation can probably be removed after a switch to OSGi 6 which will have the
* possibility to lookup bundles with the FrameworkWiring#findProviders(Requirement) method.
*/
final class BundleFinder implements BundleTrackerCustomizer<List<Bundle>> {
/** Map of bundle symbolic name to the corresponding bundles (hint: different versions). */
private final ConcurrentMap<String, List<Bundle>> trackedBundles = new ConcurrentHashMap<>();
/**
* Resolves the latest bundle with the given bundle symbolic name.
* <p>
* The latest means the bundle with the highest version.
* </p>
* @param symbolicName
* the bundle symbolic name
* @return the latest bundle with the given bundle symbolic name
*/
public Bundle findBundle(String symbolicName) {
List<Bundle> bundlesWithSameSymName = trackedBundles.get(symbolicName);
if (bundlesWithSameSymName == null)
return null;
List<Bundle> snapshot = new ArrayList<>(bundlesWithSameSymName);
switch (snapshot.size()) {
case 0:
return null;
case 1:
return snapshot.get(0);
default:
snapshot.sort(VersionComperator.INSTANCE); // sort the snapshot by version
return snapshot.get(0); // the highest is the first entry in the list
}
}
@Override
public List<Bundle> addingBundle(Bundle bundle, BundleEvent event) {
String bundleSymName = bundle.getSymbolicName();
if (bundleSymName == null) {
return null;
}
List<Bundle> bundlesWithSameSymName = trackedBundles.get(bundleSymName);
if (bundlesWithSameSymName == null) {
bundlesWithSameSymName = new CopyOnWriteArrayList<>();
if (trackedBundles.putIfAbsent(bundleSymName, bundlesWithSameSymName) != null) {
// some other thread has won the race, so we use his List object
bundlesWithSameSymName = trackedBundles.get(bundleSymName);
}
}
bundlesWithSameSymName.add(bundle);
// return the list to mark that we want to be informed about other changes of the bundle and
// to remove the bundle in the #removedBundle() method without a lookup in the
// #trackedBundles map
return bundlesWithSameSymName;
}
@Override
public void modifiedBundle(Bundle bundle, BundleEvent event, List<Bundle> bundlesWithSameSymName) {
// not of interest
}
@Override
public void removedBundle(Bundle bundle, BundleEvent event, List<Bundle> bundlesWithSameSymName) {
// the object is the list which was returned inside the #addingBundle() method and so we
// don't need a lookup in the #trackedBundles to find the list
bundlesWithSameSymName.remove(bundle);
}
/**
* A simple {@link Comparator} which orders the bundles by their version in ascending order.
*/
private static final class VersionComperator implements Comparator<Bundle> {
/** A Singleton instance of this {@link Comparator} (the compare is done state-less). */
public static final Comparator<Bundle> INSTANCE = new VersionComperator();
private VersionComperator() {
}
@Override
public int compare(Bundle bundle1, Bundle bundle2) {
if (bundle1 == null) {
return bundle2 == null ? 0 : 1; // null elements at the end of the list
}
if (bundle2 == null) {
return -1; // null elements at the end of the list
}
return bundle2.getVersion().compareTo(bundle1.getVersion()); // newest version first
}
}
}