Package org.eclipse.osgi.internal.module

Source Code of org.eclipse.osgi.internal.module.ResolverBundle

/*******************************************************************************
* Copyright (c) 2004, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.osgi.internal.module;

import java.util.*;
import java.util.Map.Entry;
import org.eclipse.osgi.internal.resolver.ExportPackageDescriptionImpl;
import org.eclipse.osgi.internal.resolver.GenericDescriptionImpl;
import org.eclipse.osgi.service.resolver.*;
import org.osgi.framework.Constants;

/*
* A companion to BundleDescription from the state used while resolving.
*/
public class ResolverBundle extends VersionSupplier implements Comparable<ResolverBundle> {
  public static final int UNRESOLVED = 0;
  public static final int RESOLVING = 1;
  public static final int RESOLVED = 2;

  private final Long bundleID;
  private BundleConstraint host;
  private ResolverImport[] imports;
  private ResolverExport[] exports;
  private BundleConstraint[] requires;
  private GenericCapability[] genericCapabilities;
  private GenericConstraint[] genericReqiures;
  // Fragment support
  private ArrayList<ResolverBundle> fragments;
  private HashMap<Long, List<ResolverExport>> fragmentExports;
  private HashMap<Long, List<ResolverImport>> fragmentImports;
  private HashMap<Long, List<BundleConstraint>> fragmentRequires;
  private HashMap<Long, List<GenericCapability>> fragmentGenericCapabilities;
  private HashMap<Long, List<GenericConstraint>> fragmentGenericRequires;
  // Flag specifying whether this bundle is resolvable
  private boolean resolvable = true;
  // Internal resolver state for this bundle
  private int state = UNRESOLVED;
  private boolean uninstalled = false;
  private final ResolverImpl resolver;
  private boolean newFragmentExports;
  private boolean newFragmentCapabilities;

  ResolverBundle(BundleDescription bundle, ResolverImpl resolver) {
    super(bundle);
    this.bundleID = new Long(bundle.getBundleId());
    this.resolver = resolver;
    initialize(bundle.isResolved());
  }

  void initialize(boolean useSelectedExports) {
    if (getBundleDescription().getHost() != null) {
      host = new BundleConstraint(this, getBundleDescription().getHost());
      exports = new ResolverExport[0];
      imports = new ResolverImport[0];
      requires = new BundleConstraint[0];
      genericReqiures = new GenericConstraint[0];
      genericCapabilities = new GenericCapability[0];
      return;
    }

    ImportPackageSpecification[] actualImports = getBundleDescription().getImportPackages();
    // Reorder imports so that optionals are at the end so that we wire statics before optionals
    List<ResolverImport> importList = new ArrayList<ResolverImport>(actualImports.length);
    for (int i = actualImports.length - 1; i >= 0; i--)
      if (ImportPackageSpecification.RESOLUTION_OPTIONAL.equals(actualImports[i].getDirective(Constants.RESOLUTION_DIRECTIVE)))
        importList.add(new ResolverImport(this, actualImports[i]));
      else
        importList.add(0, new ResolverImport(this, actualImports[i]));
    imports = importList.toArray(new ResolverImport[importList.size()]);

    ExportPackageDescription[] actualExports = useSelectedExports ? getBundleDescription().getSelectedExports() : getBundleDescription().getExportPackages();
    exports = new ResolverExport[actualExports.length];
    for (int i = 0; i < actualExports.length; i++)
      exports[i] = new ResolverExport(this, actualExports[i]);

    BundleSpecification[] actualRequires = getBundleDescription().getRequiredBundles();
    requires = new BundleConstraint[actualRequires.length];
    for (int i = 0; i < requires.length; i++)
      requires[i] = new BundleConstraint(this, actualRequires[i]);

    GenericSpecification[] actualGenericRequires = getBundleDescription().getGenericRequires();
    genericReqiures = new GenericConstraint[actualGenericRequires.length];
    for (int i = 0; i < genericReqiures.length; i++)
      genericReqiures[i] = new GenericConstraint(this, actualGenericRequires[i]);

    GenericDescription[] actualCapabilities = useSelectedExports ? getBundleDescription().getSelectedGenericCapabilities() : getBundleDescription().getGenericCapabilities();
    genericCapabilities = new GenericCapability[actualCapabilities.length];
    for (int i = 0; i < genericCapabilities.length; i++)
      genericCapabilities[i] = new GenericCapability(this, actualCapabilities[i]);

    fragments = null;
    fragmentExports = null;
    fragmentImports = null;
    fragmentRequires = null;
    fragmentGenericCapabilities = null;
    fragmentGenericRequires = null;
  }

  ResolverExport getExport(String name) {
    ResolverExport[] allExports = getExports(name);
    return allExports.length == 0 ? null : allExports[0];
  }

  ResolverExport[] getExports(String name) {
    List<ResolverExport> results = new ArrayList<ResolverExport>(1); // rare to have more than one
    // it is faster to ask the VersionHashMap for this package name and then compare the exporter to this
    List<ResolverExport> resolverExports = resolver.getResolverExports().get(name);
    for (ResolverExport export : resolverExports)
      if (export.getExporter() == this)
        results.add(export);
    return results.toArray(new ResolverExport[results.size()]);
  }

  void clearWires() {
    ResolverImport[] allImports = getImportPackages();
    for (int i = 0; i < allImports.length; i++)
      allImports[i].clearPossibleSuppliers();

    if (host != null)
      host.clearPossibleSuppliers();

    BundleConstraint[] allRequires = getRequires();
    for (int i = 0; i < allRequires.length; i++)
      allRequires[i].clearPossibleSuppliers();

    GenericConstraint[] allGenericRequires = getGenericRequires();
    for (int i = 0; i < allGenericRequires.length; i++)
      allGenericRequires[i].clearPossibleSuppliers();

    ResolverExport[] allExports = getExportPackages();
    for (int i = 0; i < allExports.length; i++)
      allExports[i].setSubstitute(null);
  }

  boolean isResolved() {
    return getState() == ResolverBundle.RESOLVED;
  }

  boolean isFragment() {
    return host != null;
  }

  int getState() {
    return state;
  }

  void setState(int state) {
    this.state = state;
  }

  private <T> List<T> getAll(T[] hostEntries, Map<Long, List<T>> fragmentMap) {
    List<T> result = new ArrayList<T>(hostEntries.length);
    for (T entry : hostEntries)
      result.add(entry);
    for (ResolverBundle fragment : fragments) {
      List<T> fragEntries = fragmentMap.get(fragment.bundleID);
      if (fragEntries != null)
        result.addAll(fragEntries);
    }
    return result;
  }

  ResolverImport[] getImportPackages() {
    if (isFragment() || fragments == null || fragments.size() == 0)
      return imports;
    List<ResolverImport> result = getAll(imports, fragmentImports);
    return result.toArray(new ResolverImport[result.size()]);
  }

  ResolverExport[] getExportPackages() {
    if (isFragment() || fragments == null || fragments.size() == 0)
      return exports;
    List<ResolverExport> result = getAll(exports, fragmentExports);
    return result.toArray(new ResolverExport[result.size()]);
  }

  ResolverExport[] getSelectedExports() {
    return getExports(true);
  }

  ResolverExport[] getSubstitutedExports() {
    return getExports(false);
  }

  private ResolverExport[] getExports(boolean selected) {
    ResolverExport[] results = getExportPackages();
    int removedExports = 0;
    for (int i = 0; i < results.length; i++)
      if (selected ? results[i].getSubstitute() != null : results[i].getSubstitute() == null)
        removedExports++;
    if (removedExports == 0)
      return results;
    ResolverExport[] selectedExports = new ResolverExport[results.length - removedExports];
    int index = 0;
    for (int i = 0; i < results.length; i++) {
      if (selected ? results[i].getSubstitute() != null : results[i].getSubstitute() == null)
        continue;
      selectedExports[index] = results[i];
      index++;
    }
    return selectedExports;
  }

  BundleConstraint getHost() {
    return host;
  }

  GenericCapability[] getGenericCapabilities() {
    if (isFragment() || fragments == null || fragments.size() == 0)
      return genericCapabilities;
    List<GenericCapability> result = getAll(genericCapabilities, fragmentGenericCapabilities);
    return result.toArray(new GenericCapability[result.size()]);
  }

  BundleConstraint[] getRequires() {
    if (isFragment() || fragments == null || fragments.size() == 0)
      return requires;
    List<BundleConstraint> result = getAll(requires, fragmentRequires);
    return result.toArray(new BundleConstraint[result.size()]);
  }

  GenericConstraint[] getGenericRequires() {
    if (isFragment() || fragments == null || fragments.size() == 0)
      return genericReqiures;
    List<GenericConstraint> result = getAll(genericReqiures, fragmentGenericRequires);
    return result.toArray(new GenericConstraint[result.size()]);
  }

  BundleConstraint getRequire(String name) {
    BundleConstraint[] allRequires = getRequires();
    for (int i = 0; i < allRequires.length; i++)
      if (allRequires[i].getVersionConstraint().getName().equals(name))
        return allRequires[i];
    return null;
  }

  public BundleDescription getBundleDescription() {
    return (BundleDescription) getBaseDescription();
  }

  public ResolverBundle getResolverBundle() {
    return this;
  }

  ResolverImport getImport(String name) {
    ResolverImport[] allImports = getImportPackages();
    for (int i = 0; i < allImports.length; i++) {
      if (allImports[i].getName().equals(name)) {
        return allImports[i];
      }
    }
    return null;
  }

  public String toString() {
    return "[" + getBundleDescription() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
  }

  private void initFragments() {
    if (fragments == null)
      fragments = new ArrayList<ResolverBundle>(1);
    if (fragmentExports == null)
      fragmentExports = new HashMap<Long, List<ResolverExport>>(1);
    if (fragmentImports == null)
      fragmentImports = new HashMap<Long, List<ResolverImport>>(1);
    if (fragmentRequires == null)
      fragmentRequires = new HashMap<Long, List<BundleConstraint>>(1);
    if (fragmentGenericCapabilities == null)
      fragmentGenericCapabilities = new HashMap<Long, List<GenericCapability>>(1);
    if (fragmentGenericRequires == null)
      fragmentGenericRequires = new HashMap<Long, List<GenericConstraint>>(1);
  }

  private boolean isImported(String packageName) {
    ResolverImport[] allImports = getImportPackages();
    for (int i = 0; i < allImports.length; i++)
      if (packageName.equals(allImports[i].getName()))
        return true;

    return false;
  }

  private boolean isRequired(String bundleName) {
    return getRequire(bundleName) != null;
  }

  void attachFragment(ResolverBundle fragment, boolean dynamicAttach) {
    if (isFragment())
      return; // cannot attach to fragments;
    if (!getBundleDescription().attachFragments() || (isResolved() && !getBundleDescription().dynamicFragments()))
      return; // host is restricting attachment
    if (fragment.getHost().getNumPossibleSuppliers() > 0 && !((HostSpecification) fragment.getHost().getVersionConstraint()).isMultiHost())
      return; // fragment is restricting attachment

    ImportPackageSpecification[] newImports = fragment.getBundleDescription().getImportPackages();
    BundleSpecification[] newRequires = fragment.getBundleDescription().getRequiredBundles();
    ExportPackageDescription[] newExports = fragment.getBundleDescription().getExportPackages();
    GenericDescription[] newGenericCapabilities = fragment.getBundleDescription().getGenericCapabilities();
    GenericSpecification[] newGenericRequires = fragment.getBundleDescription().getGenericRequires();

    // if this is not during initialization then check if constraints conflict
    if (dynamicAttach && constraintsConflict(fragment.getBundleDescription(), newImports, newRequires, newGenericRequires))
      return; // do not allow fragments with conflicting constraints
    if (isResolved() && newExports.length > 0)
      fragment.setNewFragmentExports(true);
    if (isResolved() && newGenericCapabilities.length > 0)
      fragment.setNewFragmentCapabilities(true);

    initFragments();
    // need to make sure there is not already another version of this fragment
    // already attached to this host
    for (Iterator<ResolverBundle> iFragments = fragments.iterator(); iFragments.hasNext();) {
      ResolverBundle existingFragment = iFragments.next();
      String bsn = existingFragment.getName();
      if (bsn != null && bsn.equals(fragment.getName()))
        return;
    }
    if (fragments.contains(fragment))
      return;
    fragments.add(fragment);
    fragment.getHost().addPossibleSupplier(this);

    if (newImports.length > 0) {
      ArrayList<ResolverImport> hostImports = new ArrayList<ResolverImport>(newImports.length);
      for (int i = 0; i < newImports.length; i++)
        if (!isImported(newImports[i].getName()))
          hostImports.add(new ResolverImport(this, newImports[i]));
      fragmentImports.put(fragment.bundleID, hostImports);
    }

    if (newRequires.length > 0) {
      ArrayList<BundleConstraint> hostRequires = new ArrayList<BundleConstraint>(newRequires.length);
      for (int i = 0; i < newRequires.length; i++)
        if (!isRequired(newRequires[i].getName()))
          hostRequires.add(new BundleConstraint(this, newRequires[i]));
      fragmentRequires.put(fragment.bundleID, hostRequires);
    }

    if (newGenericRequires.length > 0) {
      ArrayList<GenericConstraint> hostGenericRequires = new ArrayList<GenericConstraint>(newGenericRequires.length);
      for (int i = 0; i < newGenericRequires.length; i++)
        hostGenericRequires.add(new GenericConstraint(this, newGenericRequires[i]));
      fragmentGenericRequires.put(fragment.bundleID, hostGenericRequires);
    }

    ArrayList<ResolverExport> hostExports = new ArrayList<ResolverExport>(newExports.length);
    if (newExports.length > 0 && dynamicAttach) {
      for (int i = 0; i < newExports.length; i++) {
        ResolverExport currentExports[] = getExports(newExports[i].getName());
        boolean foundEquivalent = false;
        for (int j = 0; j < currentExports.length && !foundEquivalent; j++) {
          if (equivalentExports(currentExports[j], newExports[i]))
            foundEquivalent = true;
        }
        if (!foundEquivalent) {
          ExportPackageDescription hostExport = new ExportPackageDescriptionImpl(getBundleDescription(), newExports[i]);
          hostExports.add(new ResolverExport(this, hostExport));
        }
      }
      fragmentExports.put(fragment.bundleID, hostExports);
    }

    List<GenericCapability> hostCapabilities = new ArrayList<GenericCapability>(newGenericCapabilities.length);
    if (newGenericCapabilities.length > 0 && dynamicAttach) {
      for (GenericDescription capability : newGenericCapabilities) {
        GenericDescription hostCapabililty = new GenericDescriptionImpl(getBundleDescription(), capability);
        hostCapabilities.add(new GenericCapability(this, hostCapabililty));
      }
      fragmentGenericCapabilities.put(fragment.bundleID, hostCapabilities);
    }
    if (dynamicAttach) {
      resolver.getResolverExports().put(hostExports.toArray(new ResolverExport[hostExports.size()]));
      resolver.addGenerics(hostCapabilities.toArray(new GenericCapability[hostCapabilities.size()]));
    }
  }

  private boolean equivalentExports(ResolverExport existingExport, ExportPackageDescription newDescription) {
    ExportPackageDescription existingDescription = existingExport.getExportPackageDescription();
    if (!existingDescription.getName().equals(newDescription.getName()))
      return false;
    if (!existingDescription.getVersion().equals(newDescription.getVersion()))
      return false;
    if (!equivalentMaps(existingDescription.getAttributes(), newDescription.getAttributes(), true))
      return false;
    if (!equivalentMaps(existingDescription.getDirectives(), newDescription.getDirectives(), true))
      return false;
    return true;
  }

  public static boolean equivalentMaps(Map<String, Object> existingDirectives, Map<String, Object> newDirectives, boolean exactMatch) {
    if (existingDirectives == null && newDirectives == null)
      return true;
    if (existingDirectives == null ? newDirectives != null : newDirectives == null)
      return false;
    if (exactMatch && existingDirectives.size() != newDirectives.size())
      return false;
    for (Iterator<Entry<String, Object>> entries = existingDirectives.entrySet().iterator(); entries.hasNext();) {
      Entry<String, Object> entry = entries.next();
      Object newValue = newDirectives.get(entry.getKey());
      if (newValue == null || entry.getValue().getClass() != newValue.getClass())
        return false;
      if (newValue instanceof String[]) {
        if (!Arrays.equals((Object[]) entry.getValue(), (Object[]) newValue))
          return false;
      } else if (!entry.getValue().equals(newValue)) {
        return false;
      }
    }
    return true;
  }

  boolean constraintsConflict(BundleDescription fragment, ImportPackageSpecification[] newImports, BundleSpecification[] newRequires, GenericSpecification[] newGenericRequires) {
    // this method iterates over all additional constraints from a fragment
    // if the host is resolved then the fragment is not allowed to add new constraints;
    // if the host is resolved and it already has a constraint of the same name then ensure the supplier satisfies the fragment's constraint
    boolean result = false;
    for (int i = 0; i < newImports.length; i++) {
      ResolverImport hostImport = getImport(newImports[i].getName());
      ResolverExport resolvedExport = (ResolverExport) (hostImport == null ? null : hostImport.getSelectedSupplier());
      if ((resolvedExport == null && isResolved()) || (resolvedExport != null && !newImports[i].isSatisfiedBy(resolvedExport.getExportPackageDescription()))) {
        result = true;
        resolver.getState().addResolverError(fragment, ResolverError.FRAGMENT_CONFLICT, newImports[i].toString(), newImports[i]);
      }
    }
    for (int i = 0; i < newRequires.length; i++) {
      BundleConstraint hostRequire = getRequire(newRequires[i].getName());
      ResolverBundle resolvedRequire = (ResolverBundle) (hostRequire == null ? null : hostRequire.getSelectedSupplier());
      if ((resolvedRequire == null && isResolved()) || (resolvedRequire != null && !newRequires[i].isSatisfiedBy(resolvedRequire.getBundleDescription()))) {
        result = true;
        resolver.getState().addResolverError(fragment, ResolverError.FRAGMENT_CONFLICT, newRequires[i].toString(), newRequires[i]);
      }
    }
    // generic constraints cannot conflict;
    // only check that a fragment does not add generics constraints to an already resolved host
    if (isResolved() && newGenericRequires != null && newGenericRequires.length > 0)
      result = true;
    return result;
  }

  private void setNewFragmentExports(boolean newFragmentExports) {
    this.newFragmentExports = newFragmentExports;
  }

  boolean isNewFragmentExports() {
    return newFragmentExports;
  }

  private void setNewFragmentCapabilities(boolean newFragmentCapabilities) {
    this.newFragmentCapabilities = newFragmentCapabilities;
  }

  boolean isNewFragmentCapabilities() {
    return newFragmentCapabilities;
  }

  void detachFragment(ResolverBundle fragment, ResolverConstraint reason) {
    if (isFragment())
      return;
    initFragments();

    // must save off old imports and requires before we remove the fragment;
    // this will be used to merge the constraints of the same name from the remaining fragments
    ResolverImport[] oldImports = getImportPackages();
    BundleConstraint[] oldRequires = getRequires();
    if (!fragments.remove(fragment))
      return;

    fragment.setNewFragmentExports(false);
    fragment.setNewFragmentCapabilities(false);
    fragment.getHost().removePossibleSupplier(this);
    fragmentImports.remove(fragment.bundleID);
    fragmentRequires.remove(fragment.bundleID);
    List<ResolverExport> removedExports = fragmentExports.remove(fragment.bundleID);
    fragmentGenericRequires.remove(fragment.bundleID);
    List<GenericCapability> removedCapabilities = fragmentGenericCapabilities.remove(fragment.bundleID);
    if (reason != null) {
      // the fragment is being detached because one of its imports or requires cannot be resolved;
      // we need to check the remaining fragment constraints to make sure they do not have
      // the same unresolved constraint.
      // bug 353103: must make a snapshot to avoid ConcurrentModificationException
      ResolverBundle[] remainingFrags = fragments.toArray(new ResolverBundle[fragments.size()]);
      for (ResolverBundle remainingFrag : remainingFrags) {
        List<ResolverImport> additionalImports = new ArrayList<ResolverImport>(0);
        List<BundleConstraint> additionalRequires = new ArrayList<BundleConstraint>(0);
        if (hasUnresolvedConstraint(reason, fragment, remainingFrag, oldImports, oldRequires, additionalImports, additionalRequires))
          continue;
        // merge back the additional imports or requires which the detached fragment has in common with the remaining fragment
        if (additionalImports.size() > 0) {
          List<ResolverImport> remainingImports = fragmentImports.get(remainingFrag.bundleID);
          if (remainingImports == null)
            fragmentImports.put(remainingFrag.bundleID, additionalImports);
          else
            remainingImports.addAll(additionalImports);
        }
        if (additionalRequires.size() > 0) {
          List<BundleConstraint> remainingRequires = fragmentRequires.get(remainingFrag.bundleID);
          if (remainingRequires == null)
            fragmentRequires.put(remainingFrag.bundleID, additionalRequires);
          else
            remainingRequires.addAll(additionalRequires);
        }
      }
    }
    ResolverExport[] results = removedExports == null ? new ResolverExport[0] : removedExports.toArray(new ResolverExport[removedExports.size()]);
    for (int i = 0; i < results.length; i++)
      // TODO this is a hack; need to figure out how to indicate that a fragment export is no longer attached
      results[i].setSubstitute(results[i]);
    resolver.getResolverExports().remove(results);
    if (removedCapabilities != null)
      resolver.removeGenerics(removedCapabilities.toArray(new GenericCapability[removedCapabilities.size()]));
  }

  private boolean hasUnresolvedConstraint(ResolverConstraint reason, ResolverBundle detachedFragment, ResolverBundle remainingFragment, ResolverImport[] oldImports, BundleConstraint[] oldRequires, List<ResolverImport> additionalImports, List<BundleConstraint> additionalRequires) {
    ImportPackageSpecification[] remainingFragImports = remainingFragment.getBundleDescription().getImportPackages();
    BundleSpecification[] remainingFragRequires = remainingFragment.getBundleDescription().getRequiredBundles();
    VersionConstraint[] constraints;
    if (reason instanceof ResolverImport)
      constraints = remainingFragImports;
    else
      constraints = remainingFragRequires;
    for (int i = 0; i < constraints.length; i++)
      if (reason.getName().equals(constraints[i].getName())) {
        detachFragment(remainingFragment, reason);
        return true;
      }
    for (int i = 0; i < oldImports.length; i++) {
      if (oldImports[i].getVersionConstraint().getBundle() != detachedFragment.getBundleDescription())
        continue; // the constraint is not from the detached fragment
      for (int j = 0; j < remainingFragImports.length; j++) {
        if (oldImports[i].getName().equals(remainingFragImports[j].getName())) {
          // same constraint, must reuse the constraint object but swap out the fragment info
          additionalImports.add(oldImports[i]);
          oldImports[i].setVersionConstraint(remainingFragImports[j]);
          break;
        }
      }
    }
    for (int i = 0; i < oldRequires.length; i++) {
      if (oldRequires[i].getVersionConstraint().getBundle() != detachedFragment.getBundleDescription())
        continue; // the constraint is not from the detached fragment
      for (int j = 0; j < remainingFragRequires.length; j++) {
        if (oldRequires[i].getName().equals(remainingFragRequires[j].getName())) {
          // same constraint, must reuse the constraint object but swap out the fragment info
          additionalRequires.add(oldRequires[i]);
          oldRequires[i].setVersionConstraint(remainingFragRequires[j]);
          break;
        }
      }
    }
    return false;
  }

  void detachAllFragments() {
    if (fragments == null)
      return;
    ResolverBundle[] allFragments = fragments.toArray(new ResolverBundle[fragments.size()]);
    for (int i = 0; i < allFragments.length; i++)
      detachFragment(allFragments[i], null);
    fragments = null;
  }

  boolean isResolvable() {
    return resolvable;
  }

  void setResolvable(boolean resolvable) {
    this.resolvable = resolvable;
  }

  void addExport(ResolverExport re) {
    ResolverExport[] newExports = new ResolverExport[exports.length + 1];
    for (int i = 0; i < exports.length; i++)
      newExports[i] = exports[i];
    newExports[exports.length] = re;
    exports = newExports;
  }

  ResolverImpl getResolver() {
    return resolver;
  }

  ResolverBundle[] getFragments() {
    return fragments == null ? new ResolverBundle[0] : (ResolverBundle[]) fragments.toArray(new ResolverBundle[fragments.size()]);
  }

  /*
   * This is used to sort bundles by BSN.  This is needed to fix bug 174930
   * If both BSNs are null then 0 is returned
   * If this BSN is null the 1 is returned
   * If the other BSN is null then -1 is returned
   * otherwise String.compareTo is used
   */
  public int compareTo(ResolverBundle o) {
    String bsn = getName();
    String otherBsn = o.getName();
    if (bsn == null)
      return otherBsn == null ? 0 : 1;
    return otherBsn == null ? -1 : bsn.compareTo(otherBsn);
  }

  void setUninstalled() {
    uninstalled = true;
  }

  boolean isUninstalled() {
    return uninstalled;
  }
}
TOP

Related Classes of org.eclipse.osgi.internal.module.ResolverBundle

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.