/*******************************************************************************
 * Copyright (c) 2003, 2016 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     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<>(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 (ExportPackageDescription exportPackage : exportPackages) {
					((ExportPackageDescriptionImpl) exportPackage).setExporter(this);
				}
			}
		}
	}

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

	protected void setRequiredBundles(BundleSpecification[] requiredBundles) {
		synchronized (this.monitor) {
			checkLazyData();
			lazyData.requiredBundles = requiredBundles;
			if (requiredBundles != null)
				for (BundleSpecification requiredBundle : requiredBundles) {
					((VersionConstraintImpl) requiredBundle).setBundle(this);
				}
		}
	}

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

	protected void setGenericRequires(GenericSpecification[] genericRequires) {
		synchronized (this.monitor) {
			checkLazyData();
			lazyData.genericRequires = genericRequires;
			if (genericRequires != null)
				for (GenericSpecification genericRequire : genericRequires) {
					((VersionConstraintImpl) genericRequire).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 (NativeCodeDescription supplier : suppliers) {
						((NativeCodeDescriptionImpl) supplier).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 (ExportPackageDescription selectedExport : selectedExports) {
					((ExportPackageDescriptionImpl) selectedExport).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;
		}
	}

	@Override
	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<>(newDependencies.length);
			for (BaseDescription newDependency : newDependencies) {
				addDependency((BaseDescriptionImpl) newDependency, 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<>(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<>(0);
			ArrayList<BundleDescription> required = new ArrayList<>(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<>(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<>();
			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<>();
			}
			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<>(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<>(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<>();
		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<>();
		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;
	}

	@Override
	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());
		}

		@Override
		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<>();
			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<>(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<>();
			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<>(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<>();
				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<>(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;
		}

		@Override
		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));
	}
}
