| /******************************************************************************* |
| * Copyright (c) 2003, 2013 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.util.KeyedElement; |
| import org.eclipse.osgi.service.resolver.*; |
| import org.osgi.framework.*; |
| import org.osgi.framework.wiring.*; |
| import org.osgi.resource.*; |
| |
| 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 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 Map<String, String> arbitraryDirectives; |
| |
| 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; |
| } |
| } |
| |
| 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; |
| } |
| } |
| |
| 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); |
| } |
| } |
| } |
| |
| 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; |
| } |
| |
| @SuppressWarnings("unchecked") |
| void setArbitraryDirectives(Map<String, ?> directives) { |
| synchronized (this.monitor) { |
| this.arbitraryDirectives = (Map<String, String>) directives; |
| } |
| } |
| |
| Map<String, String> getArbitraryDirectives() { |
| synchronized (this.monitor) { |
| return arbitraryDirectives; |
| } |
| } |
| |
| public Map<String, String> getDeclaredDirectives() { |
| Map<String, String> result = new HashMap<String, String>(2); |
| Map<String, String> arbitrary = getArbitraryDirectives(); |
| if (arbitrary != null) |
| result.putAll(arbitrary); |
| 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$ |
| } |
| |
| public BundleRevision getProvider() { |
| return provider.getRevision(); |
| } |
| |
| public BundleRevision getRequirer() { |
| return requirer.getRevision(); |
| } |
| } |
| |
| /** |
| * Coerce the generic type of a list from List<BundleWire> |
| * to List<Wire> |
| * @param l List to be coerced. |
| * @return l coerced to List<Wire> |
| */ |
| @SuppressWarnings("unchecked") |
| static List<Wire> asListWire(List<? extends Wire> l) { |
| return (List<Wire>) l; |
| } |
| |
| /** |
| * Coerce the generic type of a list from List<BundleCapability> |
| * to List<Capability> |
| * @param l List to be coerced. |
| * @return l coerced to List<Capability> |
| */ |
| @SuppressWarnings("unchecked") |
| static List<Capability> asListCapability(List<? extends Capability> l) { |
| return (List<Capability>) l; |
| } |
| |
| /** |
| * Coerce the generic type of a list from List<BundleRequirement> |
| * to List<Requirement> |
| * @param l List to be coerced. |
| * @return l coerced to List<Requirement> |
| */ |
| @SuppressWarnings("unchecked") |
| static List<Requirement> asListRequirement(List<? extends Requirement> l) { |
| return (List<Requirement>) l; |
| } |
| |
| // 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; |
| List<BundleCapability> result = new ArrayList<BundleCapability>(); |
| GenericDescription[] genericCapabilities = getSelectedGenericCapabilities(); |
| for (GenericDescription capabilitiy : genericCapabilities) { |
| if (namespace == null || namespace.equals(capabilitiy.getType())) |
| result.add(capabilitiy.getCapability()); |
| } |
| if (host != null) |
| return result; |
| 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()); |
| } |
| return result; |
| } |
| |
| public List<Capability> getResourceCapabilities(String namespace) { |
| return asListCapability(getCapabilities(namespace)); |
| } |
| |
| 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 (getHost() == null && (namespace == null || BundleRevision.PACKAGE_NAMESPACE.equals(namespace))) { |
| // TODO need to handle fragments that add dynamic imports |
| 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); |
| } |
| } |
| } |
| ImportPackageSpecification[] addedDynamic = getAddedDynamicImportPackages(); |
| for (ImportPackageSpecification dynamicImport : addedDynamic) { |
| BundleRequirement req = dynamicImport.getRequirement(); |
| if (!requirements.contains(req)) |
| requirements.add(req); |
| } |
| } |
| return requirements; |
| } |
| |
| public List<Requirement> getResourceRequirements(String namespace) { |
| return asListRequirement(getRequirements(namespace)); |
| } |
| |
| 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<Wire> getProvidedResourceWires(String namespace) { |
| return asListWire(getProvidedWires(namespace)); |
| } |
| |
| public List<BundleWire> getRequiredWires(String namespace) { |
| if (!isInUse()) |
| return null; |
| List<BundleWire> result = Collections.<BundleWire> emptyList(); |
| 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 List<Wire> getRequiredResourceWires(String namespace) { |
| return asListWire(getRequiredWires(namespace)); |
| } |
| |
| public BundleRevision getRevision() { |
| return BundleDescriptionImpl.this; |
| } |
| |
| public BundleRevision getResource() { |
| return getRevision(); |
| } |
| |
| public ClassLoader getClassLoader() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public List<URL> findEntries(String path, String filePattern, int options) { |
| return null; |
| } |
| |
| public Collection<String> listResources(String path, String filePattern, int options) { |
| return null; |
| } |
| |
| public String toString() { |
| return BundleDescriptionImpl.this.toString(); |
| } |
| } |
| |
| public List<Capability> getCapabilities(String namespace) { |
| return asListCapability(getDeclaredCapabilities(namespace)); |
| } |
| |
| public List<Requirement> getRequirements(String namespace) { |
| return asListRequirement(getDeclaredRequirements(namespace)); |
| } |
| } |