blob: 2774976c4c460804a8fa88cdcbb9e3f8f8aae24f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2008 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
* Rob Harrop - SpringSource Inc. (bug 247522)
*******************************************************************************/
package org.eclipse.osgi.internal.resolver;
import java.io.*;
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.security.AccessController;
import java.util.*;
import java.util.Map.Entry;
import org.eclipse.osgi.framework.util.SecureAction;
import org.eclipse.osgi.service.resolver.*;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.Version;
/**
* This class is internally threadsafe and supports client locking. Clients must <strong>not</strong> hold the monitor for
* any {@link StateImpl} or {@link BundleDescriptionImpl} object when calling into the public methods of this class to prevent
* possible deadlock.
*/
final class StateReader {
public static final String STATE_FILE = ".state"; //$NON-NLS-1$
public static final String LAZY_FILE = ".lazy"; //$NON-NLS-1$
private static final int BUFFER_SIZE_LAZY = 4096;
private static final int BUFFER_SIZE_FULLYREAD = 16384;
private static final SecureAction secureAction = (SecureAction) AccessController.doPrivileged(SecureAction.createSecureAction());
// objectTable will be a hashmap of objects. The objects will be things
// like BundleDescription, ExportPackageDescription, Version etc.. The integer
// index value will be used in the cache to allow cross-references in the
// cached state.
final Map objectTable = Collections.synchronizedMap(new HashMap());
private final Map stringCache = Collections.synchronizedMap(new WeakHashMap());
private volatile File stateFile;
private volatile File lazyFile;
private volatile boolean lazyLoad = true;
private volatile int numBundles;
private volatile boolean accessedFlag = false;
public static final byte STATE_CACHE_VERSION = 30;
public static final byte NULL = 0;
public static final byte OBJECT = 1;
public static final byte INDEX = 2;
public StateReader() //TODO - deprecated
{
lazyLoad = false;
}
public StateReader(File stateDirectory) {
if (!stateDirectory.exists())
stateDirectory.mkdirs();
this.stateFile = new File(stateDirectory, STATE_FILE);
this.lazyFile = new File(stateDirectory, LAZY_FILE);
this.lazyLoad = false;
}
public StateReader(File stateFile, File lazyFile, boolean lazyLoad) {
this.stateFile = stateFile;
this.lazyFile = lazyFile;
this.lazyLoad = lazyLoad;
}
private void addToObjectTable(Object object, int index) {
objectTable.put(new Integer(index), object);
}
private Object getFromObjectTable(int index) {
return objectTable.get(new Integer(index));
}
private boolean readState(StateImpl state, long expectedTimestamp) throws IOException {
DataInputStream in = new DataInputStream(new BufferedInputStream(secureAction.getFileInputStream(stateFile), BUFFER_SIZE_FULLYREAD));
DataInputStream lazyIn = null;
try {
if (in.readByte() != STATE_CACHE_VERSION)
return false;
byte tag = readTag(in);
if (tag != OBJECT)
return false;
int index = in.readInt();
long timestampRead = in.readLong();
if (expectedTimestamp >= 0 && timestampRead != expectedTimestamp)
return false;
addToObjectTable(state, index);
// read the platform property keys
String[] platformPropKeys = (String[]) readPlatformProp(in);
state.addPlatformPropertyKeys(platformPropKeys);
int numSets = in.readInt();
Dictionary[] platformProps = new Dictionary[numSets];
for (int i = 0; i < numSets; i++) {
Hashtable props = new Hashtable(platformPropKeys.length);
int numProps = in.readInt();
for (int j = 0; j < numProps; j++) {
Object value = readPlatformProp(in);
if (value != null && j < platformPropKeys.length)
props.put(platformPropKeys[j], value);
}
platformProps[i] = props;
}
state.setPlatformProperties(platformProps, false);
numBundles = in.readInt();
for (int i = 0; i < numBundles; i++) {
BundleDescriptionImpl bundle = readBundleDescription(in);
state.basicAddBundle(bundle);
if (bundle.isResolved())
state.addResolvedBundle(bundle);
}
// read the DisabledInfos
int numDisableInfos = in.readInt();
for (int i = 0; i < numDisableInfos; i++) {
DisabledInfo info = readDisabledInfo(in);
state.addDisabledInfo(info);
}
state.setTimeStamp(timestampRead);
state.setResolved(in.readBoolean());
if (lazyLoad)
return true;
//read in from lazy data file; using the fully read buffer size because we are reading the complete file in.
lazyIn = new DataInputStream(new BufferedInputStream(secureAction.getFileInputStream(lazyFile), BUFFER_SIZE_FULLYREAD));
for (int i = 0; i < numBundles; i++)
readBundleDescriptionLazyData(lazyIn, 0);
} finally {
in.close();
if (lazyIn != null)
try {
lazyIn.close();
} catch (IOException e) {
// ignore
}
}
return true;
}
private boolean readStateDeprecated(StateImpl state, DataInputStream in, long expectedTimestamp) throws IOException {
if (in.readByte() != STATE_CACHE_VERSION)
return false;
byte tag = readTag(in);
if (tag != OBJECT)
return false;
int index = in.readInt();
long timestampRead = in.readLong();
if (expectedTimestamp >= 0 && timestampRead != expectedTimestamp)
return false;
addToObjectTable(state, index);
// read the platform property keys
String[] platformPropKeys = (String[]) readPlatformProp(in);
state.addPlatformPropertyKeys(platformPropKeys);
int numSets = in.readInt();
Dictionary[] platformProps = new Dictionary[numSets];
for (int i = 0; i < numSets; i++) {
Hashtable props = new Hashtable(platformPropKeys.length);
int numProps = in.readInt();
for (int j = 0; j < numProps; j++) {
Object value = readPlatformProp(in);
if (value != null && j < platformPropKeys.length)
props.put(platformPropKeys[j], value);
}
platformProps[i] = props;
}
state.setPlatformProperties(platformProps);
numBundles = in.readInt();
if (numBundles == 0)
return true;
for (int i = 0; i < numBundles; i++) {
BundleDescriptionImpl bundle = readBundleDescription(in);
state.basicAddBundle(bundle);
if (bundle.isResolved())
state.addResolvedBundle(bundle);
}
state.setTimeStamp(timestampRead);
state.setResolved(in.readBoolean());
in.readInt(); // skip past the old offset
if (lazyLoad)
return true;
for (int i = 0; i < numBundles; i++)
readBundleDescriptionLazyData(in, 0);
return true;
}
private Object readPlatformProp(DataInputStream in) throws IOException {
byte type = in.readByte();
if (type == NULL)
return null;
int num = in.readInt();
if (num == 1)
return readString(in, false);
String[] result = new String[num];
for (int i = 0; i < result.length; i++)
result[i] = readString(in, false);
return result;
}
private BundleDescriptionImpl readBundleDescription(DataInputStream in) throws IOException {
byte tag = readTag(in);
if (tag == NULL)
return null;
if (tag == INDEX)
return (BundleDescriptionImpl) getFromObjectTable(in.readInt());
// first read in non-lazy loaded data
BundleDescriptionImpl result = new BundleDescriptionImpl();
addToObjectTable(result, in.readInt());
result.setBundleId(in.readLong());
readBaseDescription(result, in);
result.setLazyDataOffset(in.readInt());
result.setLazyDataSize(in.readInt());
result.setStateBit(BundleDescriptionImpl.RESOLVED, in.readBoolean());
result.setStateBit(BundleDescriptionImpl.SINGLETON, in.readBoolean());
result.setStateBit(BundleDescriptionImpl.HAS_DYNAMICIMPORT, in.readBoolean());
result.setStateBit(BundleDescriptionImpl.ATTACH_FRAGMENTS, in.readBoolean());
result.setStateBit(BundleDescriptionImpl.DYNAMIC_FRAGMENTS, in.readBoolean());
result.setHost(readHostSpec(in));
// set the bundle dependencies from imports and requires and hosts.
int numDeps = in.readInt();
if (numDeps > 0) {
BundleDescription[] deps = new BundleDescription[numDeps];
for (int i = 0; i < numDeps; i++)
deps[i] = readBundleDescription(in);
result.addDependencies(deps, false); // no need to check dups; we already know there are none when we resolved (bug 152900)
}
// No need to set the dependencies between fragment and hosts; that was already done in the above loop (bug 152900)
// but we do need to set the dependencies between hosts and fragment.
HostSpecificationImpl hostSpec = (HostSpecificationImpl) result.getHost();
if (hostSpec != null) {
BundleDescription[] hosts = hostSpec.getHosts();
if (hosts != null) {
for (int i = 0; i < hosts.length; i++)
((BundleDescriptionImpl) hosts[i]).addDependency(result, false);
}
}
// the rest is lazy loaded data
result.setFullyLoaded(false);
return result;
}
private BundleDescriptionImpl readBundleDescriptionLazyData(DataInputStream in, int skip) throws IOException {
if (skip > 0)
in.skipBytes(skip);
int index = in.readInt();
BundleDescriptionImpl result = (BundleDescriptionImpl) getFromObjectTable(index);
if (result.isFullyLoaded()) {
in.skipBytes(result.getLazyDataSize() - 4); // skip to the end subtract 4 for the int read already
return result;
}
result.setLocation(readString(in, false));
result.setPlatformFilter(readString(in, false));
int exportCount = in.readInt();
if (exportCount > 0) {
ExportPackageDescription[] exports = new ExportPackageDescription[exportCount];
for (int i = 0; i < exports.length; i++)
exports[i] = readExportPackageDesc(in);
result.setExportPackages(exports);
}
int importCount = in.readInt();
if (importCount > 0) {
ImportPackageSpecification[] imports = new ImportPackageSpecification[importCount];
for (int i = 0; i < imports.length; i++)
imports[i] = readImportPackageSpec(in);
result.setImportPackages(imports);
}
int requiredBundleCount = in.readInt();
if (requiredBundleCount > 0) {
BundleSpecification[] requiredBundles = new BundleSpecification[requiredBundleCount];
for (int i = 0; i < requiredBundles.length; i++)
requiredBundles[i] = readBundleSpec(in);
result.setRequiredBundles(requiredBundles);
}
int selectedCount = in.readInt();
if (selectedCount > 0) {
ExportPackageDescription[] selected = new ExportPackageDescription[selectedCount];
for (int i = 0; i < selected.length; i++)
selected[i] = readExportPackageDesc(in);
result.setSelectedExports(selected);
}
int substitutedCount = in.readInt();
if (substitutedCount > 0) {
ExportPackageDescription[] selected = new ExportPackageDescription[substitutedCount];
for (int i = 0; i < selected.length; i++)
selected[i] = readExportPackageDesc(in);
result.setSubstitutedExports(selected);
}
int resolvedCount = in.readInt();
if (resolvedCount > 0) {
ExportPackageDescription[] resolved = new ExportPackageDescription[resolvedCount];
for (int i = 0; i < resolved.length; i++)
resolved[i] = readExportPackageDesc(in);
result.setResolvedImports(resolved);
}
int resolvedRequiredCount = in.readInt();
if (resolvedRequiredCount > 0) {
BundleDescription[] resolved = new BundleDescription[resolvedRequiredCount];
for (int i = 0; i < resolved.length; i++)
resolved[i] = readBundleDescription(in);
result.setResolvedRequires(resolved);
}
int eeCount = in.readInt();
if (eeCount > 0) {
String[] ee = new String[eeCount];
for (int i = 0; i < ee.length; i++)
ee[i] = readString(in, false);
result.setExecutionEnvironments(ee);
}
int dynamicPkgCnt = in.readInt();
if (dynamicPkgCnt > 0) {
HashMap dynamicStamps = new HashMap(dynamicPkgCnt);
for (int i = 0; i < dynamicPkgCnt; i++) {
String pkg = readString(in, false);
Long stamp = new Long(in.readLong());
dynamicStamps.put(pkg, stamp);
}
result.setDynamicStamps(dynamicStamps);
}
int genericCapCnt = in.readInt();
if (genericCapCnt > 0) {
GenericDescription[] capabilities = new GenericDescription[genericCapCnt];
for (int i = 0; i < capabilities.length; i++)
capabilities[i] = readGenericDescription(in);
result.setGenericCapabilities(capabilities);
}
int genericReqCnt = in.readInt();
if (genericReqCnt > 0) {
GenericSpecification[] reqs = new GenericSpecification[genericReqCnt];
for (int i = 0; i < reqs.length; i++)
reqs[i] = readGenericSpecification(in);
result.setGenericRequires(reqs);
}
result.setNativeCodeSpecification(readNativeCode(in));
result.setFullyLoaded(true); // set fully loaded before setting the dependencies
// No need to add bundle dependencies for hosts, imports or requires;
// This is done by readBundleDescription
return result;
}
private BundleSpecificationImpl readBundleSpec(DataInputStream in) throws IOException {
BundleSpecificationImpl result = new BundleSpecificationImpl();
readVersionConstraint(result, in);
result.setSupplier(readBundleDescription(in));
result.setExported(in.readBoolean());
result.setOptional(in.readBoolean());
return result;
}
private ExportPackageDescriptionImpl readExportPackageDesc(DataInputStream in) throws IOException {
byte tag = readTag(in);
if (tag == NULL)
return null;
if (tag == INDEX)
return (ExportPackageDescriptionImpl) getFromObjectTable(in.readInt());
ExportPackageDescriptionImpl exportPackageDesc = new ExportPackageDescriptionImpl();
int tableIndex = in.readInt();
addToObjectTable(exportPackageDesc, tableIndex);
exportPackageDesc.setTableIndex(tableIndex);
readBaseDescription(exportPackageDesc, in);
exportPackageDesc.setExporter(readBundleDescription(in));
exportPackageDesc.setAttributes(readMap(in));
exportPackageDesc.setDirectives(readMap(in));
return exportPackageDesc;
}
private DisabledInfo readDisabledInfo(DataInputStream in) throws IOException {
return new DisabledInfo(readString(in, false), readString(in, false), readBundleDescription(in));
}
private Map readMap(DataInputStream in) throws IOException {
int count = in.readInt();
if (count == 0)
return null;
HashMap result = new HashMap(count);
for (int i = 0; i < count; i++) {
String key = readString(in, false);
Object value = null;
byte type = in.readByte();
if (type == 0)
value = readString(in, false);
else if (type == 1)
value = readList(in);
else if (type == 2)
value = in.readBoolean() ? Boolean.TRUE : Boolean.FALSE;
else if (type == 3)
value = new Integer(in.readInt());
else if (type == 4)
value = new Long(in.readLong());
else if (type == 5)
value = new Double(in.readDouble());
else if (type == 6)
value = readVersion(in);
else if (type == 7) {
value = readString(in, false);
try {
Class uriClazz = Class.forName("java.net.URI"); //$NON-NLS-1$
Constructor constructor = uriClazz.getConstructor(new Class[] {String.class});
value = constructor.newInstance(new Object[] {value});
} catch (ClassNotFoundException e) {
// oh well cannot support; just use the string
} catch (Exception e) { // got some reflection exception
if (e instanceof RuntimeException)
throw (RuntimeException) e;
throw new RuntimeException(e.getMessage());
}
}
result.put(key, value);
}
return result;
}
private String[] readList(DataInputStream in) throws IOException {
int count = in.readInt();
if (count == 0)
return null;
String[] result = new String[count];
for (int i = 0; i < count; i++)
result[i] = readString(in, false);
return result;
}
private void readBaseDescription(BaseDescriptionImpl root, DataInputStream in) throws IOException {
root.setName(readString(in, false));
root.setVersion(readVersion(in));
}
private ImportPackageSpecificationImpl readImportPackageSpec(DataInputStream in) throws IOException {
ImportPackageSpecificationImpl result = new ImportPackageSpecificationImpl();
readVersionConstraint(result, in);
result.setSupplier(readExportPackageDesc(in));
result.setBundleSymbolicName(readString(in, false));
result.setBundleVersionRange(readVersionRange(in));
result.setAttributes(readMap(in));
result.setDirectives(readMap(in));
return result;
}
private HostSpecificationImpl readHostSpec(DataInputStream in) throws IOException {
byte tag = readTag(in);
if (tag == NULL)
return null;
HostSpecificationImpl result = new HostSpecificationImpl();
readVersionConstraint(result, in);
int hostCount = in.readInt();
if (hostCount > 0) {
BundleDescription[] hosts = new BundleDescription[hostCount];
for (int i = 0; i < hosts.length; i++)
hosts[i] = readBundleDescription(in);
result.setHosts(hosts);
}
return result;
}
private GenericDescription readGenericDescription(DataInputStream in) throws IOException {
byte tag = readTag(in);
if (tag == NULL)
return null;
if (tag == INDEX)
return (GenericDescription) getFromObjectTable(in.readInt());
int tableIndex = in.readInt();
GenericDescriptionImpl result = new GenericDescriptionImpl();
addToObjectTable(result, tableIndex);
readBaseDescription(result, in);
result.setSupplier(readBundleDescription(in));
result.setType(readString(in, false));
Map mapAttrs = readMap(in);
Dictionary attrs = new Hashtable();
if (mapAttrs != null) {
for (Iterator keys = mapAttrs.keySet().iterator(); keys.hasNext();) {
Object key = keys.next();
attrs.put(key, mapAttrs.get(key));
}
}
result.setAttributes(attrs);
return result;
}
private GenericSpecification readGenericSpecification(DataInputStream in) throws IOException {
GenericSpecificationImpl result = new GenericSpecificationImpl();
readVersionConstraint(result, in);
result.setType(readString(in, false));
int num = in.readInt();
GenericDescription[] suppliers = num == 0 ? null : new GenericDescription[num];
for (int i = 0; i < num; i++)
suppliers[i] = readGenericDescription(in);
result.setSupplers(suppliers);
result.setResolution(in.readInt());
try {
result.setMatchingFilter(readString(in, false));
} catch (InvalidSyntaxException e) {
// do nothing this filter was tested before
}
return result;
}
private NativeCodeSpecification readNativeCode(DataInputStream in) throws IOException {
if (!in.readBoolean())
return null;
NativeCodeSpecificationImpl result = new NativeCodeSpecificationImpl();
result.setOptional(in.readBoolean());
int numNativeDesc = in.readInt();
NativeCodeDescriptionImpl[] nativeDescs = new NativeCodeDescriptionImpl[numNativeDesc];
for (int i = 0; i < numNativeDesc; i++)
nativeDescs[i] = readNativeCodeDescription(in);
result.setPossibleSuppliers(nativeDescs);
int supplierIndex = in.readInt();
if (supplierIndex >= 0)
result.setSupplier(nativeDescs[supplierIndex]);
return result;
}
private NativeCodeDescriptionImpl readNativeCodeDescription(DataInputStream in) throws IOException {
NativeCodeDescriptionImpl result = new NativeCodeDescriptionImpl();
readBaseDescription(result, in);
result.setSupplier(readBundleDescription(in));
try {
result.setFilter(readString(in, false));
} catch (InvalidSyntaxException e) {
// do nothing, this filter was tested before
}
result.setLanguages(readStringArray(in));
result.setNativePaths(readStringArray(in));
result.setOSNames(readStringArray(in));
result.setOSVersions(readVersionRanges(in));
result.setProcessors(readStringArray(in));
result.setInvalidNativePaths(in.readBoolean());
return result;
}
private VersionRange[] readVersionRanges(DataInputStream in) throws IOException {
int num = in.readInt();
if (num == 0)
return null;
VersionRange[] result = new VersionRange[num];
for (int i = 0; i < num; i++)
result[i] = readVersionRange(in);
return result;
}
private String[] readStringArray(DataInputStream in) throws IOException {
int num = in.readInt();
if (num == 0)
return null;
String[] result = new String[num];
for (int i = 0; i < num; i++)
result[i] = readString(in, false);
return result;
}
// called by readers for VersionConstraintImpl subclasses
private void readVersionConstraint(VersionConstraintImpl version, DataInputStream in) throws IOException {
version.setName(readString(in, false));
version.setVersionRange(readVersionRange(in));
}
private Version readVersion(DataInputStream in) throws IOException {
byte tag = readTag(in);
if (tag == NULL)
return Version.emptyVersion;
int majorComponent = in.readInt();
int minorComponent = in.readInt();
int serviceComponent = in.readInt();
String qualifierComponent = readString(in, false);
Version result = new Version(majorComponent, minorComponent, serviceComponent, qualifierComponent);
return result;
}
private VersionRange readVersionRange(DataInputStream in) throws IOException {
byte tag = readTag(in);
if (tag == NULL)
return null;
return new VersionRange(readVersion(in), in.readBoolean(), readVersion(in), in.readBoolean());
}
/**
* expectedTimestamp is the expected value for the timestamp. or -1, if
* no checking should be performed
*/
public synchronized boolean loadStateDeprecated(StateImpl state, DataInputStream input, long expectedTimestamp) throws IOException {
try {
return readStateDeprecated(state, input, expectedTimestamp);
} finally {
input.close();
}
}
/**
* expectedTimestamp is the expected value for the timestamp. or -1, if
* no checking should be performed
*/
public synchronized boolean loadState(StateImpl state, long expectedTimestamp) throws IOException {
return readState(state, expectedTimestamp);
}
private String readString(DataInputStream in, boolean intern) throws IOException {
byte type = in.readByte();
if (type == NULL)
return null;
String result;
if (intern)
result = in.readUTF().intern();
else
result = in.readUTF();
WeakReference ref = (WeakReference) stringCache.get(result);
if (ref != null) {
String refString = (String) ref.get();
if (refString != null)
result = refString;
} else
stringCache.put(result, new WeakReference(result));
return result;
}
private byte readTag(DataInputStream in) throws IOException {
return in.readByte();
}
private DataInputStream openLazyFile() throws IOException {
if (lazyFile == null)
throw new IOException(); // TODO error message here!
return new DataInputStream(new BufferedInputStream(secureAction.getFileInputStream(lazyFile), BUFFER_SIZE_LAZY));
}
boolean isLazyLoaded() {
return lazyLoad;
}
boolean getAccessedFlag() {
return accessedFlag;
}
void setAccessedFlag(boolean accessedFlag) {
this.accessedFlag = accessedFlag;
}
synchronized void fullyLoad() {
setAccessedFlag(true);
DataInputStream in = null;
try {
in = openLazyFile();
for (int i = 0; i < numBundles; i++)
readBundleDescriptionLazyData(in, 0);
} catch (IOException ioe) {
throw new RuntimeException(); // TODO need error message here
} finally {
if (in != null)
try {
in.close();
} catch (IOException e) {
// nothing we can do now
}
}
}
synchronized void fullyLoad(BundleDescriptionImpl target) throws IOException {
setAccessedFlag(true);
DataInputStream in = null;
try {
in = openLazyFile();
// get the set of bundles that must be loaded according to dependencies
ArrayList toLoad = new ArrayList();
addDependencies(target, toLoad);
int skipBytes[] = getSkipBytes(toLoad);
// look for the lazy data of the toLoad list
for (int i = 0; i < skipBytes.length; i++)
readBundleDescriptionLazyData(in, skipBytes[i]);
} finally {
if (in != null)
in.close();
}
}
private void addDependencies(BundleDescriptionImpl target, List toLoad) {
if (toLoad.contains(target) || target.isFullyLoaded())
return;
Iterator load = toLoad.iterator();
int i = 0;
while (load.hasNext()) {
// insert the target into the list sorted by lazy data offsets
BundleDescriptionImpl bundle = (BundleDescriptionImpl) load.next();
if (target.getLazyDataOffset() < bundle.getLazyDataOffset())
break;
i++;
}
if (i >= toLoad.size())
toLoad.add(target);
else
toLoad.add(i, target);
List deps = target.getBundleDependencies();
for (Iterator iter = deps.iterator(); iter.hasNext();)
addDependencies((BundleDescriptionImpl) iter.next(), toLoad);
}
private int[] getSkipBytes(ArrayList toLoad) {
int[] skipBytes = new int[toLoad.size()];
for (int i = 0; i < skipBytes.length; i++) {
BundleDescriptionImpl current = (BundleDescriptionImpl) toLoad.get(i);
if (i == 0) {
skipBytes[i] = current.getLazyDataOffset();
continue;
}
BundleDescriptionImpl previous = (BundleDescriptionImpl) toLoad.get(i - 1);
skipBytes[i] = current.getLazyDataOffset() - previous.getLazyDataOffset() - previous.getLazyDataSize();
}
return skipBytes;
}
void flushLazyObjectCache() {
for (Iterator entries = objectTable.entrySet().iterator(); entries.hasNext();) {
Map.Entry entry = (Entry) entries.next();
if (entry.getValue() instanceof ExportPackageDescription || entry.getValue() instanceof GenericDescription)
entries.remove();
}
}
}