Package org.eclipse.osgi.internal.resolver

Source Code of org.eclipse.osgi.internal.resolver.BundleDescriptionImpl

/*******************************************************************************
* Copyright (c) 2003, 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
*     Danail Nachev -  ProSyst - bug 218625
*     Rob Harrop - SpringSource Inc. (bug 247522 and 255520)
*******************************************************************************/
package org.eclipse.osgi.internal.resolver;

import java.io.IOException;
import java.net.URL;
import java.util.*;
import org.eclipse.osgi.framework.adaptor.BundleClassLoader;
import org.eclipse.osgi.framework.internal.core.BundleHost;
import org.eclipse.osgi.framework.internal.core.Constants;
import org.eclipse.osgi.framework.util.KeyedElement;
import org.eclipse.osgi.internal.loader.BundleLoaderProxy;
import org.eclipse.osgi.service.resolver.*;
import org.osgi.framework.*;
import org.osgi.framework.wiring.*;

public final class BundleDescriptionImpl extends BaseDescriptionImpl implements BundleDescription, KeyedElement {
  static final String[] EMPTY_STRING = new String[0];
  static final ImportPackageSpecification[] EMPTY_IMPORTS = new ImportPackageSpecification[0];
  static final BundleSpecification[] EMPTY_BUNDLESPECS = new BundleSpecification[0];
  static final ExportPackageDescription[] EMPTY_EXPORTS = new ExportPackageDescription[0];
  static final BundleDescription[] EMPTY_BUNDLEDESCS = new BundleDescription[0];
  static final GenericSpecification[] EMPTY_GENERICSPECS = new GenericSpecification[0];
  static final GenericDescription[] EMPTY_GENERICDESCS = new GenericDescription[0];
  static final RuntimePermission GET_CLASSLOADER_PERM = new RuntimePermission("getClassLoader"); //$NON-NLS-1$

  static final int RESOLVED = 0x01;
  static final int SINGLETON = 0x02;
  static final int REMOVAL_PENDING = 0x04;
  static final int FULLY_LOADED = 0x08;
  static final int LAZY_LOADED = 0x10;
  static final int HAS_DYNAMICIMPORT = 0x20;
  static final int ATTACH_FRAGMENTS = 0x40;
  static final int DYNAMIC_FRAGMENTS = 0x80;

  // set to fully loaded and allow dynamic fragments by default
  private volatile int stateBits = FULLY_LOADED | ATTACH_FRAGMENTS | DYNAMIC_FRAGMENTS;

  private volatile long bundleId = -1;
  volatile HostSpecification host; //null if the bundle is not a fragment. volatile to allow unsynchronized checks for null
  private volatile StateImpl containingState;

  private volatile Object userObject;
  private volatile int lazyDataOffset = -1;
  private volatile int lazyDataSize = -1;

  private List<BundleDescription> dependencies;
  private List<BundleDescription> dependents;
  private String[] mandatory;
  private Map<String, Object> attributes;

  private volatile LazyData lazyData;
  private volatile int equinox_ee = -1;

  private DescriptionWiring bundleWiring;

  public BundleDescriptionImpl() {
    //
  }

  public long getBundleId() {
    return bundleId;
  }

  public String getSymbolicName() {
    return getName();
  }

  public BundleDescription getSupplier() {
    return this;
  }

  public String getLocation() {
    LazyData currentData = loadLazyData();
    synchronized (this.monitor) {
      return currentData.location;
    }
  }

  public String getPlatformFilter() {
    LazyData currentData = loadLazyData();
    synchronized (this.monitor) {
      return currentData.platformFilter;
    }
  }

  public String[] getExecutionEnvironments() {
    LazyData currentData = loadLazyData();
    synchronized (this.monitor) {
      if (currentData.executionEnvironments == null)
        return EMPTY_STRING;
      return currentData.executionEnvironments;
    }
  }

  public ImportPackageSpecification[] getImportPackages() {
    LazyData currentData = loadLazyData();
    synchronized (this.monitor) {
      if (currentData.importPackages == null)
        return EMPTY_IMPORTS;
      return currentData.importPackages;
    }
  }

  public ImportPackageSpecification[] getAddedDynamicImportPackages() {
    LazyData currentData = loadLazyData();
    synchronized (this.monitor) {
      if (currentData.addedDynamicImports == null)
        return EMPTY_IMPORTS;
      return currentData.addedDynamicImports.toArray(new ImportPackageSpecification[currentData.addedDynamicImports.size()]);
    }
  }

  public BundleSpecification[] getRequiredBundles() {
    LazyData currentData = loadLazyData();
    synchronized (this.monitor) {
      if (currentData.requiredBundles == null)
        return EMPTY_BUNDLESPECS;
      return currentData.requiredBundles;
    }
  }

  public GenericSpecification[] getGenericRequires() {
    LazyData currentData = loadLazyData();
    synchronized (this.monitor) {
      if (currentData.genericRequires == null)
        return EMPTY_GENERICSPECS;
      return currentData.genericRequires;
    }
  }

  public GenericDescription[] getGenericCapabilities() {
    LazyData currentData = loadLazyData();
    synchronized (this.monitor) {
      if (currentData.genericCapabilities == null)
        return EMPTY_GENERICDESCS;
      return currentData.genericCapabilities;
    }
  }

  public NativeCodeSpecification getNativeCodeSpecification() {
    LazyData currentData = loadLazyData();
    synchronized (this.monitor) {
      return currentData.nativeCode;
    }
  }

  public ExportPackageDescription[] getExportPackages() {
    LazyData currentData = loadLazyData();
    synchronized (this.monitor) {
      return currentData.exportPackages == null ? EMPTY_EXPORTS : currentData.exportPackages;
    }
  }

  public boolean isResolved() {
    return (stateBits & RESOLVED) != 0;
  }

  public State getContainingState() {
    return containingState;
  }

  public BundleDescription[] getFragments() {
    if (host != null)
      return EMPTY_BUNDLEDESCS;
    StateImpl currentState = (StateImpl) getContainingState();
    if (currentState == null)
      throw new IllegalStateException("BundleDescription does not belong to a state."); //$NON-NLS-1$
    return currentState.getFragments(this);
  }

  public HostSpecification getHost() {
    return host;
  }

  public boolean isSingleton() {
    return (stateBits & SINGLETON) != 0;
  }

  public boolean isRemovalPending() {
    return (stateBits & REMOVAL_PENDING) != 0;
  }

  public boolean hasDynamicImports() {
    return (stateBits & HAS_DYNAMICIMPORT) != 0;
  }

  public boolean attachFragments() {
    return (stateBits & ATTACH_FRAGMENTS) != 0;
  }

  public boolean dynamicFragments() {
    return (stateBits & DYNAMIC_FRAGMENTS) != 0;
  }

  public ExportPackageDescription[] getSelectedExports() {
    LazyData currentData = loadLazyData();
    synchronized (this.monitor) {
      if (currentData.selectedExports == null)
        return EMPTY_EXPORTS;
      return currentData.selectedExports;
    }
  }

  public GenericDescription[] getSelectedGenericCapabilities() {
    LazyData currentData = loadLazyData();
    synchronized (this.monitor) {
      if (currentData.selectedCapabilities == null)
        return EMPTY_GENERICDESCS;
      return currentData.selectedCapabilities;
    }
  }

  public ExportPackageDescription[] getSubstitutedExports() {
    LazyData currentData = loadLazyData();
    synchronized (this.monitor) {
      if (currentData.substitutedExports == null)
        return EMPTY_EXPORTS;
      return currentData.substitutedExports;
    }
  }

  public BundleDescription[] getResolvedRequires() {
    LazyData currentData = loadLazyData();
    synchronized (this.monitor) {
      if (currentData.resolvedRequires == null)
        return EMPTY_BUNDLEDESCS;
      return currentData.resolvedRequires;
    }
  }

  public ExportPackageDescription[] getResolvedImports() {
    LazyData currentData = loadLazyData();
    synchronized (this.monitor) {
      if (currentData.resolvedImports == null)
        return EMPTY_EXPORTS;
      return currentData.resolvedImports;
    }
  }

  public GenericDescription[] getResolvedGenericRequires() {
    LazyData currentData = loadLazyData();
    synchronized (this.monitor) {
      if (currentData.resolvedCapabilities == null)
        return EMPTY_GENERICDESCS;
      return currentData.resolvedCapabilities;
    }
  }

  public Map<String, List<StateWire>> getWires() {
    LazyData currentData = loadLazyData();
    synchronized (this.monitor) {
      if (currentData.stateWires == null) {
        currentData.stateWires = new HashMap<String, List<StateWire>>(0);
      }
      return currentData.stateWires;
    }
  }

  Map<String, List<StateWire>> getWiresInternal() {
    LazyData currentData = loadLazyData();
    synchronized (this.monitor) {
      return currentData.stateWires;
    }
  }

  protected void setBundleId(long bundleId) {
    this.bundleId = bundleId;
  }

  protected void setSymbolicName(String symbolicName) {
    setName(symbolicName);
  }

  protected void setLocation(String location) {
    synchronized (this.monitor) {
      checkLazyData();
      lazyData.location = location;
    }
  }

  protected void setPlatformFilter(String platformFilter) {
    synchronized (this.monitor) {
      checkLazyData();
      lazyData.platformFilter = platformFilter;
    }
  }

  protected void setExecutionEnvironments(String[] executionEnvironments) {
    synchronized (this.monitor) {
      checkLazyData();
      lazyData.executionEnvironments = executionEnvironments;
    }
  }

  protected void setExportPackages(ExportPackageDescription[] exportPackages) {
    synchronized (this.monitor) {
      checkLazyData();
      lazyData.exportPackages = exportPackages;
      if (exportPackages != null) {
        for (int i = 0; i < exportPackages.length; i++) {
          ((ExportPackageDescriptionImpl) exportPackages[i]).setExporter(this);
        }
      }
    }
  }

  protected void setImportPackages(ImportPackageSpecification[] importPackages) {
    synchronized (this.monitor) {
      checkLazyData();
      lazyData.importPackages = importPackages;
      if (importPackages != null) {
        for (int i = 0; i < importPackages.length; i++) {
          ((ImportPackageSpecificationImpl) importPackages[i]).setBundle(this);
          if (ImportPackageSpecification.RESOLUTION_DYNAMIC.equals(importPackages[i].getDirective(Constants.RESOLUTION_DIRECTIVE)))
            stateBits |= HAS_DYNAMICIMPORT;
        }
      }
    }
  }

  protected void setRequiredBundles(BundleSpecification[] requiredBundles) {
    synchronized (this.monitor) {
      checkLazyData();
      lazyData.requiredBundles = requiredBundles;
      if (requiredBundles != null)
        for (int i = 0; i < requiredBundles.length; i++) {
          ((VersionConstraintImpl) requiredBundles[i]).setBundle(this);
        }
    }
  }

  protected void setGenericCapabilities(GenericDescription[] genericCapabilities) {
    synchronized (this.monitor) {
      checkLazyData();
      lazyData.genericCapabilities = genericCapabilities;
      if (genericCapabilities != null)
        for (int i = 0; i < genericCapabilities.length; i++)
          ((GenericDescriptionImpl) genericCapabilities[i]).setSupplier(this);
    }
  }

  protected void setGenericRequires(GenericSpecification[] genericRequires) {
    synchronized (this.monitor) {
      checkLazyData();
      lazyData.genericRequires = genericRequires;
      if (genericRequires != null)
        for (int i = 0; i < genericRequires.length; i++)
          ((VersionConstraintImpl) genericRequires[i]).setBundle(this);
    }
  }

  protected void setNativeCodeSpecification(NativeCodeSpecification nativeCode) {
    synchronized (this.monitor) {
      checkLazyData();
      lazyData.nativeCode = nativeCode;
      if (nativeCode != null) {
        ((NativeCodeSpecificationImpl) nativeCode).setBundle(this);
        NativeCodeDescription[] suppliers = nativeCode.getPossibleSuppliers();
        if (suppliers != null)
          for (int i = 0; i < suppliers.length; i++)
            ((NativeCodeDescriptionImpl) suppliers[i]).setSupplier(this);
      }
    }
  }

  protected int getStateBits() {
    return stateBits;
  }

  protected void setStateBit(int stateBit, boolean on) {
    synchronized (this.monitor) {
      if (on) {
        stateBits |= stateBit;
      } else {
        stateBits &= ~stateBit;
        if (stateBit == RESOLVED) {
          if (bundleWiring != null)
            bundleWiring.invalidate();
          bundleWiring = null;
        }
      }
    }
  }

  protected void setContainingState(State value) {
    synchronized (this.monitor) {
      containingState = (StateImpl) value;
      if (containingState != null && containingState.getReader() != null) {
        if (containingState.getReader().isLazyLoaded())
          stateBits |= LAZY_LOADED;
        else
          stateBits &= ~LAZY_LOADED;
      } else {
        stateBits &= ~LAZY_LOADED;
      }
    }
  }

  protected void setHost(HostSpecification host) {
    synchronized (this.monitor) {
      this.host = host;
      if (host != null) {
        ((VersionConstraintImpl) host).setBundle(this);
      }
    }
  }

  protected void setLazyLoaded(boolean lazyLoad) {
    loadLazyData();
    synchronized (this.monitor) {
      if (lazyLoad)
        stateBits |= LAZY_LOADED;
      else
        stateBits &= ~LAZY_LOADED;
    }
  }

  protected void setSelectedExports(ExportPackageDescription[] selectedExports) {
    synchronized (this.monitor) {
      checkLazyData();
      lazyData.selectedExports = selectedExports;
      if (selectedExports != null) {
        for (int i = 0; i < selectedExports.length; i++) {
          ((ExportPackageDescriptionImpl) selectedExports[i]).setExporter(this);
        }
      }
    }
  }

  protected void setSelectedCapabilities(GenericDescription[] selectedCapabilities) {
    synchronized (this.monitor) {
      checkLazyData();
      lazyData.selectedCapabilities = selectedCapabilities;
      if (selectedCapabilities != null) {
        for (GenericDescription capability : selectedCapabilities) {
          ((GenericDescriptionImpl) capability).setSupplier(this);
        }
      }
    }
  }

  protected void setSubstitutedExports(ExportPackageDescription[] substitutedExports) {
    synchronized (this.monitor) {
      checkLazyData();
      lazyData.substitutedExports = substitutedExports;
    }
  }

  protected void setResolvedImports(ExportPackageDescription[] resolvedImports) {
    synchronized (this.monitor) {
      checkLazyData();
      lazyData.resolvedImports = resolvedImports;
    }
  }

  protected void setResolvedRequires(BundleDescription[] resolvedRequires) {
    synchronized (this.monitor) {
      checkLazyData();
      lazyData.resolvedRequires = resolvedRequires;
    }
  }

  protected void setResolvedCapabilities(GenericDescription[] resolvedCapabilities) {
    synchronized (this.monitor) {
      checkLazyData();
      lazyData.resolvedCapabilities = resolvedCapabilities;
    }
  }

  protected void setStateWires(Map<String, List<StateWire>> stateWires) {
    synchronized (this.monitor) {
      checkLazyData();
      lazyData.stateWires = stateWires;
    }
  }

  void clearAddedDynamicImportPackages() {
    synchronized (this.monitor) {
      checkLazyData();
      lazyData.addedDynamicImports = null;
    }
  }

  public String toString() {
    if (getSymbolicName() == null)
      return "[" + getBundleId() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
    return getSymbolicName() + "_" + getVersion(); //$NON-NLS-1$
  }

  public Object getKey() {
    return new Long(bundleId);
  }

  public boolean compare(KeyedElement other) {
    if (!(other instanceof BundleDescriptionImpl))
      return false;
    BundleDescriptionImpl otherBundleDescription = (BundleDescriptionImpl) other;
    return bundleId == otherBundleDescription.bundleId;
  }

  public int getKeyHashCode() {
    return (int) (bundleId ^ (bundleId >>> 32));
  }

  /* TODO Determine if we need more than just Object ID type of hashcode.
   public int hashCode() {
   if (getSymbolicName() == null)
   return (int) (bundleId % Integer.MAX_VALUE);
   return (int) ((bundleId * (getSymbolicName().hashCode())) % Integer.MAX_VALUE);
   }
   */

  protected void removeDependencies() {
    synchronized (this.monitor) {
      if (dependencies == null)
        return;
      Iterator<BundleDescription> iter = dependencies.iterator();
      while (iter.hasNext()) {
        ((BundleDescriptionImpl) iter.next()).removeDependent(this);
      }
      dependencies = null;
    }
  }

  protected void addDependencies(BaseDescription[] newDependencies, boolean checkDups) {
    synchronized (this.monitor) {
      if (newDependencies == null)
        return;
      if (!checkDups && dependencies == null)
        dependencies = new ArrayList<BundleDescription>(newDependencies.length);
      for (int i = 0; i < newDependencies.length; i++) {
        addDependency((BaseDescriptionImpl) newDependencies[i], checkDups);
      }
    }
  }

  protected void addDependency(BaseDescriptionImpl dependency, boolean checkDups) {
    synchronized (this.monitor) {
      BundleDescriptionImpl bundle = (BundleDescriptionImpl) dependency.getSupplier();
      if (bundle == this)
        return;
      if (dependencies == null)
        dependencies = new ArrayList<BundleDescription>(10);
      if (!checkDups || !dependencies.contains(bundle)) {
        bundle.addDependent(this);
        dependencies.add(bundle);
      }
    }
  }

  /*
   * Gets all the bundle dependencies as a result of import-package or require-bundle.
   * Self and fragment bundles are removed.
   */
  List<BundleDescription> getBundleDependencies() {
    synchronized (this.monitor) {
      if (dependencies == null)
        return new ArrayList<BundleDescription>(0);
      ArrayList<BundleDescription> required = new ArrayList<BundleDescription>(dependencies.size());
      for (Iterator<BundleDescription> iter = dependencies.iterator(); iter.hasNext();) {
        BundleDescription dep = iter.next();
        if (dep != this && dep.getHost() == null)
          required.add(dep);
      }
      return required;
    }
  }

  public Object getUserObject() {
    return userObject;
  }

  public void setUserObject(Object userObject) {
    this.userObject = userObject;
  }

  protected void addDependent(BundleDescription dependent) {
    synchronized (this.monitor) {
      if (dependents == null)
        dependents = new ArrayList<BundleDescription>(10);
      // no need to check for duplicates here; this is only called in addDepenency which already checks for dups.
      dependents.add(dependent);
    }
  }

  protected void removeDependent(BundleDescription dependent) {
    synchronized (this.monitor) {
      if (dependents == null)
        return;
      dependents.remove(dependent);
    }
  }

  public BundleDescription[] getDependents() {
    synchronized (this.monitor) {
      if (dependents == null)
        return EMPTY_BUNDLEDESCS;
      return dependents.toArray(new BundleDescription[dependents.size()]);
    }
  }

  boolean hasDependents() {
    synchronized (this.monitor) {
      return dependents == null ? false : dependents.size() > 0;
    }
  }

  void setFullyLoaded(boolean fullyLoaded) {
    synchronized (this.monitor) {
      if (fullyLoaded) {
        stateBits |= FULLY_LOADED;
      } else {
        stateBits &= ~FULLY_LOADED;
      }
    }
  }

  boolean isFullyLoaded() {
    return (stateBits & FULLY_LOADED) != 0;
  }

  void setLazyDataOffset(int lazyDataOffset) {
    this.lazyDataOffset = lazyDataOffset;
  }

  int getLazyDataOffset() {
    return this.lazyDataOffset;
  }

  void setLazyDataSize(int lazyDataSize) {
    this.lazyDataSize = lazyDataSize;
  }

  int getLazyDataSize() {
    return this.lazyDataSize;
  }

  // DO NOT call while holding this.monitor
  private LazyData loadLazyData() {
    // TODO add back if ee min 1.2 adds holdsLock method
    //if (Thread.holdsLock(this.monitor)) {
    //  throw new IllegalStateException("Should not call fullyLoad() holding monitor."); //$NON-NLS-1$
    //}
    if ((stateBits & LAZY_LOADED) == 0)
      return this.lazyData;

    StateImpl currentState = (StateImpl) getContainingState();
    StateReader reader = currentState == null ? null : currentState.getReader();
    if (reader == null)
      throw new IllegalStateException("No valid reader for the bundle description"); //$NON-NLS-1$

    synchronized (currentState.monitor) {
      if (isFullyLoaded()) {
        reader.setAccessedFlag(true); // set reader accessed flag
        return this.lazyData;
      }
      try {
        reader.fullyLoad(this);
        return this.lazyData;
      } catch (IOException e) {
        throw new RuntimeException(e.getMessage(), e); // TODO not sure what to do here!!
      }
    }
  }

  void addDynamicResolvedImport(ExportPackageDescriptionImpl result) {
    synchronized (this.monitor) {
      // mark the dependency
      addDependency(result, true);
      // add the export to the list of the resolvedImports
      checkLazyData();
      if (lazyData.resolvedImports == null) {
        lazyData.resolvedImports = new ExportPackageDescription[] {result};
        return;
      }
      ExportPackageDescription[] newImports = new ExportPackageDescription[lazyData.resolvedImports.length + 1];
      System.arraycopy(lazyData.resolvedImports, 0, newImports, 0, lazyData.resolvedImports.length);
      newImports[newImports.length - 1] = result;
      lazyData.resolvedImports = newImports;
    }
    setLazyLoaded(false);
  }

  void addDynamicImportPackages(ImportPackageSpecification[] dynamicImport) {
    LazyData currentData = loadLazyData();
    synchronized (this.monitor) {
      if (currentData.addedDynamicImports == null)
        currentData.addedDynamicImports = new ArrayList<ImportPackageSpecification>();
      for (ImportPackageSpecification addImport : dynamicImport) {
        if (!ImportPackageSpecification.RESOLUTION_DYNAMIC.equals(addImport.getDirective(Constants.RESOLUTION_DIRECTIVE)))
          throw new IllegalArgumentException("Import must be a dynamic import."); //$NON-NLS-1$
      }
      adding: for (ImportPackageSpecification addImport : dynamicImport) {
        for (ImportPackageSpecification currentImport : currentData.addedDynamicImports) {
          if (equalImports(addImport, currentImport))
            continue adding;
        }
        ((ImportPackageSpecificationImpl) addImport).setBundle(this);
        currentData.addedDynamicImports.add(addImport);
      }
    }
    setLazyLoaded(false);
  }

  private boolean equalImports(ImportPackageSpecification addImport, ImportPackageSpecification currentImport) {
    if (!isEqual(addImport.getName(), currentImport.getName()))
      return false;
    if (!isEqual(addImport.getVersionRange(), currentImport.getVersionRange()))
      return false;
    if (!isEqual(addImport.getBundleSymbolicName(), currentImport.getBundleSymbolicName()))
      return false;
    if (!isEqual(addImport.getBundleVersionRange(), currentImport.getBundleVersionRange()))
      return false;
    return isEqual(addImport.getAttributes(), currentImport.getAttributes());
  }

  private boolean isEqual(Object o1, Object o2) {
    return (o1 == null) ? o2 == null : o1.equals(o2);
  }

  void unload() {
    StateImpl currentState = (StateImpl) getContainingState();
    StateReader reader = currentState == null ? null : currentState.getReader();
    if (reader == null)
      throw new IllegalStateException("BundleDescription does not belong to a reader."); //$NON-NLS-1$
    synchronized (currentState.monitor) {
      if ((stateBits & LAZY_LOADED) == 0)
        return;
      if (!isFullyLoaded())
        return;
      synchronized (this.monitor) {
        setFullyLoaded(false);
        lazyData = null;
      }
    }
  }

  void setDynamicStamps(Map<String, Long> dynamicStamps) {
    synchronized (this.monitor) {
      checkLazyData();
      lazyData.dynamicStamps = dynamicStamps;
    }
  }

  void setDynamicStamp(String requestedPackage, Long timestamp) {
    synchronized (this.monitor) {
      checkLazyData();
      if (lazyData.dynamicStamps == null) {
        if (timestamp == null)
          return;
        lazyData.dynamicStamps = new HashMap<String, Long>();
      }
      if (timestamp == null)
        lazyData.dynamicStamps.remove(requestedPackage);
      else
        lazyData.dynamicStamps.put(requestedPackage, timestamp);
    }
  }

  long getDynamicStamp(String requestedPackage) {
    LazyData currentData = loadLazyData();
    synchronized (this.monitor) {
      Long stamp = currentData.dynamicStamps == null ? null : (Long) currentData.dynamicStamps.get(requestedPackage);
      return stamp == null ? 0 : stamp.longValue();
    }
  }

  Map<String, Long> getDynamicStamps() {
    LazyData currentData = loadLazyData();
    synchronized (this.monitor) {
      return currentData.dynamicStamps;
    }
  }

  public void setEquinoxEE(int equinox_ee) {
    this.equinox_ee = equinox_ee;
  }

  public int getEquinoxEE() {
    return equinox_ee;
  }

  private void checkLazyData() {
    if (lazyData == null)
      lazyData = new LazyData();
  }

  final class LazyData {
    String location;
    String platformFilter;

    BundleSpecification[] requiredBundles;
    ExportPackageDescription[] exportPackages;
    ImportPackageSpecification[] importPackages;
    GenericDescription[] genericCapabilities;
    GenericSpecification[] genericRequires;
    NativeCodeSpecification nativeCode;

    ExportPackageDescription[] selectedExports;
    GenericDescription[] selectedCapabilities;
    BundleDescription[] resolvedRequires;
    ExportPackageDescription[] resolvedImports;
    GenericDescription[] resolvedCapabilities;
    ExportPackageDescription[] substitutedExports;
    String[] executionEnvironments;

    Map<String, Long> dynamicStamps;
    Map<String, List<StateWire>> stateWires;
    // Note that this is not persisted in the state cache
    List<ImportPackageSpecification> addedDynamicImports;
  }

  public Map<String, Object> getAttributes() {
    synchronized (this.monitor) {
      return attributes;
    }
  }

  @SuppressWarnings("unchecked")
  void setAttributes(Map<String, ?> attributes) {
    synchronized (this.monitor) {
      this.attributes = (Map<String, Object>) attributes;
    }
  }

  Object getDirective(String key) {
    synchronized (this.monitor) {
      if (Constants.MANDATORY_DIRECTIVE.equals(key))
        return mandatory;
      if (Constants.SINGLETON_DIRECTIVE.equals(key))
        return isSingleton() ? Boolean.TRUE : Boolean.FALSE;
      if (Constants.FRAGMENT_ATTACHMENT_DIRECTIVE.equals(key)) {
        if (!attachFragments())
          return Constants.FRAGMENT_ATTACHMENT_NEVER;
        if (dynamicFragments())
          return Constants.FRAGMENT_ATTACHMENT_ALWAYS;
        return Constants.FRAGMENT_ATTACHMENT_RESOLVETIME;
      }
    }
    return null;
  }

  void setDirective(String key, Object value) {
    // only pay attention to mandatory directive for now; others are set with setState method
    if (Constants.MANDATORY_DIRECTIVE.equals(key))
      mandatory = (String[]) value;
  }

  public Map<String, String> getDeclaredDirectives() {
    Map<String, String> result = new HashMap<String, String>(2);
    if (!attachFragments()) {
      result.put(Constants.FRAGMENT_ATTACHMENT_DIRECTIVE, Constants.FRAGMENT_ATTACHMENT_NEVER);
    } else {
      if (dynamicFragments())
        result.put(Constants.FRAGMENT_ATTACHMENT_DIRECTIVE, Constants.FRAGMENT_ATTACHMENT_ALWAYS);
      else
        result.put(Constants.FRAGMENT_ATTACHMENT_DIRECTIVE, Constants.FRAGMENT_ATTACHMENT_RESOLVETIME);
    }
    if (isSingleton())
      result.put(Constants.SINGLETON_DIRECTIVE, Boolean.TRUE.toString());
    String[] mandatoryDirective = (String[]) getDirective(Constants.MANDATORY_DIRECTIVE);
    if (mandatoryDirective != null)
      result.put(Constants.MANDATORY_DIRECTIVE, ExportPackageDescriptionImpl.toString(mandatoryDirective));
    return Collections.unmodifiableMap(result);
  }

  public Map<String, Object> getDeclaredAttributes() {
    Map<String, Object> result = new HashMap<String, Object>(1);
    synchronized (this.monitor) {
      if (attributes != null)
        result.putAll(attributes);
    }
    result.put(BundleRevision.BUNDLE_NAMESPACE, getName());
    result.put(Constants.BUNDLE_VERSION_ATTRIBUTE, getVersion());
    return Collections.unmodifiableMap(result);
  }

  public List<BundleRequirement> getDeclaredRequirements(String namespace) {
    List<BundleRequirement> result = new ArrayList<BundleRequirement>();
    if (namespace == null || BundleRevision.BUNDLE_NAMESPACE.equals(namespace)) {
      BundleSpecification[] requires = getRequiredBundles();
      for (BundleSpecification require : requires) {
        result.add(require.getRequirement());
      }
    }
    if (host != null && (namespace == null || BundleRevision.HOST_NAMESPACE.equals(namespace))) {
      result.add(host.getRequirement());
    }
    if (namespace == null || BundleRevision.PACKAGE_NAMESPACE.equals(namespace)) {
      ImportPackageSpecification[] imports = getImportPackages();
      for (ImportPackageSpecification importPkg : imports)
        result.add(importPkg.getRequirement());
    }
    GenericSpecification[] genericSpecifications = getGenericRequires();
    for (GenericSpecification requirement : genericSpecifications) {
      if (namespace == null || namespace.equals(requirement.getType()))
        result.add(requirement.getRequirement());
    }
    return Collections.unmodifiableList(result);
  }

  public List<BundleCapability> getDeclaredCapabilities(String namespace) {
    List<BundleCapability> result = new ArrayList<BundleCapability>();
    if (host == null) {
      if (getSymbolicName() != null) {
        if (namespace == null || BundleRevision.BUNDLE_NAMESPACE.equals(namespace)) {
          result.add(BundleDescriptionImpl.this.getCapability());
        }
        if (attachFragments() && (namespace == null || BundleRevision.HOST_NAMESPACE.equals(namespace))) {
          result.add(BundleDescriptionImpl.this.getCapability(BundleRevision.HOST_NAMESPACE));
        }
      }

    } else {
      // may need to have a osgi.wiring.fragment capability
    }
    if (namespace == null || BundleRevision.PACKAGE_NAMESPACE.equals(namespace)) {
      ExportPackageDescription[] exports = getExportPackages();
      for (ExportPackageDescription exportPkg : exports)
        result.add(exportPkg.getCapability());
    }
    GenericDescription[] genericCapabilities = getGenericCapabilities();
    for (GenericDescription capabilitiy : genericCapabilities) {
      if (namespace == null || namespace.equals(capabilitiy.getType()))
        result.add(capabilitiy.getCapability());
    }
    return Collections.unmodifiableList(result);
  }

  public int getTypes() {
    return getHost() != null ? BundleRevision.TYPE_FRAGMENT : 0;
  }

  public Bundle getBundle() {
    Object ref = getUserObject();
    if (ref instanceof BundleReference)
      return ((BundleReference) ref).getBundle();
    return null;
  }

  String getInternalNameSpace() {
    return BundleRevision.BUNDLE_NAMESPACE;
  }

  public BundleWiring getWiring() {
    synchronized (this.monitor) {
      if (bundleWiring != null || !isResolved())
        return bundleWiring;
      return bundleWiring = new DescriptionWiring();
    }
  }

  static class BundleWireImpl implements BundleWire {
    private final BundleCapability capability;
    private final BundleWiring provider;
    private final BundleRequirement requirement;
    private final BundleWiring requirer;

    public BundleWireImpl(StateWire wire) {
      VersionConstraint declaredRequirement = wire.getDeclaredRequirement();
      if (declaredRequirement instanceof HostSpecification)
        this.capability = ((BaseDescriptionImpl) wire.getDeclaredCapability()).getCapability(BundleRevision.HOST_NAMESPACE);
      else
        this.capability = wire.getDeclaredCapability().getCapability();
      this.provider = wire.getCapabilityHost().getWiring();
      this.requirement = declaredRequirement.getRequirement();
      this.requirer = wire.getRequirementHost().getWiring();
    }

    public BundleCapability getCapability() {
      return capability;
    }

    public BundleRequirement getRequirement() {
      return requirement;
    }

    public BundleWiring getProviderWiring() {
      return provider;
    }

    public BundleWiring getRequirerWiring() {
      return requirer;
    }

    @Override
    public int hashCode() {
      int hashcode = 31 + capability.hashCode();
      hashcode = hashcode * 31 + requirement.hashCode();
      hashcode = hashcode * 31 + provider.hashCode();
      hashcode = hashcode * 31 + requirer.hashCode();
      return hashcode;
    }

    @Override
    public boolean equals(Object obj) {
      if (!(obj instanceof BundleWireImpl))
        return false;
      BundleWireImpl other = (BundleWireImpl) obj;
      return capability.equals(other.getCapability()) && requirement.equals(other.getRequirement()) && provider.equals(other.getProviderWiring()) && requirer.equals(other.getRequirerWiring());
    }

    public String toString() {
      return getRequirement() + " -> " + getCapability(); //$NON-NLS-1$
    }
  }

  // Note that description wiring are identity equality based
  class DescriptionWiring implements BundleWiring {
    private volatile boolean valid = true;

    public Bundle getBundle() {
      return BundleDescriptionImpl.this.getBundle();
    }

    public boolean isInUse() {
      return valid && (isCurrent() || BundleDescriptionImpl.this.hasDependents());
    }

    void invalidate() {
      valid = false;
    }

    public boolean isCurrent() {
      return valid && !BundleDescriptionImpl.this.isRemovalPending();
    }

    public List<BundleCapability> getCapabilities(String namespace) {
      if (!isInUse())
        return null;
      @SuppressWarnings("unchecked")
      List<BundleCapability> result = Collections.EMPTY_LIST;
      if (host != null)
        return result;
      result = new ArrayList<BundleCapability>();
      if (getSymbolicName() != null) {
        if (namespace == null || BundleRevision.BUNDLE_NAMESPACE.equals(namespace)) {
          result.add(BundleDescriptionImpl.this.getCapability());
        }
        if (attachFragments() && (namespace == null || BundleRevision.HOST_NAMESPACE.equals(namespace))) {
          result.add(BundleDescriptionImpl.this.getCapability(BundleRevision.HOST_NAMESPACE));
        }
      }
      if (namespace == null || BundleRevision.PACKAGE_NAMESPACE.equals(namespace)) {
        ExportPackageDescription[] exports = getSelectedExports();
        for (ExportPackageDescription exportPkg : exports)
          result.add(exportPkg.getCapability());
      }
      GenericDescription[] genericCapabilities = getSelectedGenericCapabilities();
      for (GenericDescription capabilitiy : genericCapabilities) {
        if (namespace == null || namespace.equals(capabilitiy.getType()))
          result.add(capabilitiy.getCapability());
      }
      return result;
    }

    public List<BundleRequirement> getRequirements(String namespace) {
      List<BundleWire> requiredWires = getRequiredWires(namespace);
      if (requiredWires == null)
        // happens if not in use
        return null;
      List<BundleRequirement> requirements = new ArrayList<BundleRequirement>(requiredWires.size());
      for (BundleWire wire : requiredWires) {
        if (!requirements.contains(wire.getRequirement()))
          requirements.add(wire.getRequirement());
      }
      // get dynamic imports
      if (namespace == null || BundleRevision.PACKAGE_NAMESPACE.equals(namespace)) {
        if (hasDynamicImports()) {
          ImportPackageSpecification[] imports = getImportPackages();
          for (ImportPackageSpecification impPackage : imports) {
            if (ImportPackageSpecification.RESOLUTION_DYNAMIC.equals(impPackage.getDirective(Constants.RESOLUTION_DIRECTIVE))) {
              BundleRequirement req = impPackage.getRequirement();
              if (!requirements.contains(req))
                requirements.add(req);
            }
          }
        }
      }
      return requirements;
    }

    public List<BundleWire> getProvidedWires(String namespace) {
      if (!isInUse())
        return null;
      BundleDescription[] dependentBundles = getDependents();
      List<BundleWire> unorderedResult = new ArrayList<BundleWire>();
      for (BundleDescription dependent : dependentBundles) {
        List<BundleWire> dependentWires = dependent.getWiring().getRequiredWires(namespace);
        if (dependentWires != null)
          for (BundleWire bundleWire : dependentWires) {
            if (bundleWire.getProviderWiring() == this)
              unorderedResult.add(bundleWire);
          }
      }
      List<BundleWire> orderedResult = new ArrayList<BundleWire>(unorderedResult.size());
      List<BundleCapability> capabilities = getCapabilities(namespace);
      for (BundleCapability capability : capabilities) {
        for (Iterator<BundleWire> wires = unorderedResult.iterator(); wires.hasNext();) {
          BundleWire wire = wires.next();
          if (wire.getCapability().equals(capability)) {
            wires.remove();
            orderedResult.add(wire);
          }
        }
      }
      return orderedResult;
    }

    public List<BundleWire> getRequiredWires(String namespace) {
      if (!isInUse())
        return null;
      @SuppressWarnings("unchecked")
      List<BundleWire> result = Collections.EMPTY_LIST;
      Map<String, List<StateWire>> wireMap = getWires();
      if (namespace == null) {
        result = new ArrayList<BundleWire>();
        for (List<StateWire> wires : wireMap.values()) {
          for (StateWire wire : wires) {
            result.add(new BundleWireImpl(wire));
          }
        }
        return result;
      }
      List<StateWire> wires = wireMap.get(namespace);
      if (wires == null)
        return result;
      result = new ArrayList<BundleWire>(wires.size());
      for (StateWire wire : wires) {
        result.add(new BundleWireImpl(wire));
      }
      return result;
    }

    public BundleRevision getRevision() {
      return BundleDescriptionImpl.this;
    }

    public ClassLoader getClassLoader() {
      SecurityManager sm = System.getSecurityManager();
      if (sm != null)
        sm.checkPermission(GET_CLASSLOADER_PERM);
      if (!isInUse())
        return null;
      return (ClassLoader) getBundleClassLoader();
    }

    private BundleClassLoader getBundleClassLoader() {
      Object o = BundleDescriptionImpl.this.getUserObject();
      if (!(o instanceof BundleLoaderProxy)) {
        if (o instanceof BundleReference)
          o = ((BundleReference) o).getBundle();
        if (o instanceof BundleHost)
          o = ((BundleHost) o).getLoaderProxy();
      }
      if (o instanceof BundleLoaderProxy)
        return ((BundleLoaderProxy) o).getBundleLoader().createClassLoader();
      return null;
    }

    private boolean hasResourcePermission() {
      SecurityManager sm = System.getSecurityManager();
      if (sm != null) {
        try {
          sm.checkPermission(new AdminPermission(getBundle(), AdminPermission.RESOURCE));
        } catch (SecurityException e) {
          return false;
        }
      }
      return true;
    }

    public List<URL> findEntries(String path, String filePattern, int options) {
      if (!hasResourcePermission() || !isInUse())
        return null;
      @SuppressWarnings("unchecked")
      List<URL> result = Collections.EMPTY_LIST;
      BundleClassLoader bcl = getBundleClassLoader();
      if (bcl != null)
        result = bcl.findEntries(path, filePattern, options);
      return Collections.unmodifiableList(result);
    }

    public Collection<String> listResources(String path, String filePattern, int options) {
      if (!hasResourcePermission() || !isInUse())
        return null;
      @SuppressWarnings("unchecked")
      Collection<String> result = Collections.EMPTY_LIST;
      BundleClassLoader bcl = getBundleClassLoader();
      if (bcl != null)
        result = bcl.listResources(path, filePattern, options);
      return Collections.unmodifiableCollection(result);
    }

    public String toString() {
      return BundleDescriptionImpl.this.toString();
    }
  }
}
TOP

Related Classes of org.eclipse.osgi.internal.resolver.BundleDescriptionImpl

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.