org.eclipse.core.internal.registry.RegistryObjectManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aspectjtools Show documentation
Show all versions of aspectjtools Show documentation
AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during
compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based
@AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step.
This library is a superset of AspectJ weaver and hence also of AspectJ runtime.
/*******************************************************************************
* Copyright (c) 2004, 2018 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
*******************************************************************************/
package org.eclipse.core.internal.registry;
import java.lang.ref.SoftReference;
import java.util.*;
import org.eclipse.core.runtime.IContributor;
import org.eclipse.core.runtime.InvalidRegistryObjectException;
import org.eclipse.core.runtime.spi.RegistryContributor;
/**
* This class manage all the object from the registry but does not deal with their dependencies.
* It serves the objects which are either directly obtained from memory or read from a cache.
* It also returns handles for objects.
*/
public class RegistryObjectManager implements IObjectManager {
//Constants used to get the objects and their handles
static public final byte CONFIGURATION_ELEMENT = 1;
static public final byte EXTENSION = 2;
static public final byte EXTENSION_POINT = 3;
static public final byte THIRDLEVEL_CONFIGURATION_ELEMENT = 4;
static final int CACHE_INITIAL_SIZE = 512; //This value has been picked because it is the minimal size required to startup an RCP app. (FYI, eclipse requires 3 growths).
static final float DEFAULT_LOADFACTOR = 0.75f; //This is the default factor used in reference map.
static final int[] EMPTY_INT_ARRAY = new int[0];
static final String[] EMPTY_STRING_ARRAY = new String[0];
static final ExtensionHandle[] EMPTY_EXTENSIONS_ARRAY = new ExtensionHandle[0];
static int UNKNOWN = -1;
// key: extensionPointName, value: object id
private HashtableOfStringAndInt extensionPoints; //This is loaded on startup. Then entries can be added when loading a new plugin from the xml.
// key: object id, value: an object
private ReferenceMap cache; //Entries are added by getter. The structure is not thread safe.
//key: int, value: int
private OffsetTable fileOffsets = null; //This is read once on startup when loading from the cache. Entries are never added here. They are only removed to prevent "removed" objects to be reloaded.
private int nextId = 1; //This is only used to get the next number available.
//Those two data structures are only used when the addition or the removal of a plugin occurs.
//They are used to keep track on a contributor basis of the extension being added or removed
private final KeyedHashSet newContributions; //represents the contributers added during this session.
private Object formerContributions; //represents the contributers encountered in previous sessions. This is loaded lazily.
private HashMap contributors; // key: contributor ID; value: contributor name
private HashMap removedContributors; // key: contributor ID; value: contributor name
private KeyedHashSet namespacesIndex; // registry elements (extension & extensionpoints) indexed by namespaces
// Map key: extensionPointFullyQualifiedName, value int[] of orphan extensions.
// The orphan access does not need to be synchronized because the it is protected by the lock in extension registry.
private Object orphanExtensions;
private final KeyedHashSet heldObjects = new KeyedHashSet(); //strong reference to the objects that must be hold on to
//Indicate if objects have been removed or added from the table. This only needs to be set in a couple of places (addNamespace and removeNamespace)
private boolean isDirty = false;
private boolean fromCache = false;
private final ExtensionRegistry registry;
// TODO this option is not used
// OSGI system properties. Copied from EclipseStarter
public static final String PROP_NO_REGISTRY_FLUSHING = "eclipse.noRegistryFlushing"; //$NON-NLS-1$
public RegistryObjectManager(ExtensionRegistry registry) {
extensionPoints = new HashtableOfStringAndInt();
if ("true".equalsIgnoreCase(RegistryProperties.getProperty(PROP_NO_REGISTRY_FLUSHING))) { //$NON-NLS-1$
cache = new ReferenceMap(ReferenceMap.HARD, CACHE_INITIAL_SIZE, DEFAULT_LOADFACTOR);
} else {
cache = new ReferenceMap(ReferenceMap.SOFT, CACHE_INITIAL_SIZE, DEFAULT_LOADFACTOR);
}
newContributions = new KeyedHashSet();
this.registry = registry;
}
/**
* Initialize the object manager. Return true if the initialization succeeded, false otherwise
*/
synchronized boolean init(long timeStamp) {
TableReader reader = registry.getTableReader();
Object[] results = reader.loadTables(timeStamp);
if (results == null) {
return false;
}
fileOffsets = (OffsetTable) results[0];
extensionPoints = (HashtableOfStringAndInt) results[1];
nextId = ((Integer) results[2]).intValue();
fromCache = true;
if (!registry.useLazyCacheLoading()) {
//TODO Here we could grow all the tables to the right size (ReferenceMap)
reader.setHoldObjects(true);
markOrphansHasDirty(getOrphans());
fromCache = reader.readAllCache(this);
formerContributions = getFormerContributions();
}
return fromCache;
}
synchronized void addContribution(Contribution contribution) {
isDirty = true;
Object Id = contribution.getKey();
KeyedElement existingContribution = getFormerContributions().getByKey(Id);
if (existingContribution != null) { // move it from former to new contributions
removeContribution(Id);
newContributions.add(existingContribution);
} else
existingContribution = newContributions.getByKey(Id);
if (existingContribution != null) // merge
((Contribution) existingContribution).mergeContribution(contribution);
else
newContributions.add(contribution);
updateNamespaceIndex(contribution, true);
}
// TODO make ExtensionPoint, Extension provide namespace in a same way (move it to the RegistryObject?)
// See if all the registryObjects have the same namespace. If not, return null.
// Also can return null if empty array is passed in or objects are of an unexpected type
private String findCommonNamespaceIdentifier(RegistryObject[] registryObjects) {
String namespaceName = null;
for (RegistryObject currentObject : registryObjects) {
String tmp = null;
if (currentObject instanceof ExtensionPoint)
tmp = ((ExtensionPoint) currentObject).getNamespace();
else if (currentObject instanceof Extension)
tmp = ((Extension) currentObject).getNamespaceIdentifier();
if (namespaceName == null) {
namespaceName = tmp;
continue;
}
if (!namespaceName.equals(tmp)) {
return null;
}
}
return namespaceName;
}
synchronized void removeExtensionPointFromNamespaceIndex(int extensionPoint, String namespaceName) {
RegistryIndexElement indexElement = getNamespaceIndex(namespaceName);
indexElement.updateExtensionPoint(extensionPoint, false);
}
synchronized void removeExtensionFromNamespaceIndex(int extensions, String namespaceName) {
RegistryIndexElement indexElement = getNamespaceIndex(namespaceName);
indexElement.updateExtension(extensions, false);
}
// Called from a synchronized method
private void updateNamespaceIndex(Contribution contribution, boolean added) {
// if all extension points are from the same namespace combine them in one block and add them all together
int[] contribExtensionPoints = contribution.getExtensionPoints();
RegistryObject[] extensionPointObjects = getObjects(contribExtensionPoints, EXTENSION_POINT);
String commonExptsNamespace = null;
if (contribExtensionPoints.length > 1)
commonExptsNamespace = findCommonNamespaceIdentifier(extensionPointObjects);
if (commonExptsNamespace != null) {
RegistryIndexElement indexElement = getNamespaceIndex(commonExptsNamespace);
indexElement.updateExtensionPoints(contribExtensionPoints, added);
} else {
for (int i = 0; i < contribExtensionPoints.length; i++) {
String namespaceName = ((ExtensionPoint) extensionPointObjects[i]).getNamespace();
RegistryIndexElement indexElement = getNamespaceIndex(namespaceName);
indexElement.updateExtensionPoint(contribExtensionPoints[i], added);
}
}
// if all extensions are from the same namespace combine them in one block and add them all together
int[] contrExtensions = contribution.getExtensions();
RegistryObject[] extensionObjects = getObjects(contrExtensions, EXTENSION);
String commonExtNamespace = null;
if (contrExtensions.length > 1)
commonExtNamespace = findCommonNamespaceIdentifier(extensionObjects);
if (commonExtNamespace != null) {
RegistryIndexElement indexElement = getNamespaceIndex(commonExtNamespace);
indexElement.updateExtensions(contrExtensions, added);
} else {
for (int i = 0; i < contrExtensions.length; i++) {
String namespaceName = ((Extension) extensionObjects[i]).getNamespaceIdentifier();
RegistryIndexElement indexElement = getNamespaceIndex(namespaceName);
indexElement.updateExtension(contrExtensions[i], added);
}
}
}
synchronized int[] getExtensionPointsFrom(String id) {
KeyedElement tmp = newContributions.getByKey(id);
if (tmp == null)
tmp = getFormerContributions().getByKey(id);
if (tmp == null)
return EMPTY_INT_ARRAY;
return ((Contribution) tmp).getExtensionPoints();
}
synchronized boolean hasContribution(String id) {
Object result = newContributions.getByKey(id);
if (result == null)
result = getFormerContributions().getByKey(id);
return result != null;
}
private KeyedHashSet getFormerContributions() {
KeyedHashSet result;
if (fromCache == false)
return new KeyedHashSet(0);
if (formerContributions == null || (result = ((KeyedHashSet) ((formerContributions instanceof SoftReference) ? ((SoftReference) formerContributions).get() : formerContributions))) == null) {
result = registry.getTableReader().loadContributions();
formerContributions = new SoftReference<>(result);
}
return result;
}
synchronized public void add(RegistryObject registryObject, boolean hold) {
if (registryObject.getObjectId() == UNKNOWN) {
int id = nextId++;
registryObject.setObjectId(id);
}
cache.put(registryObject.getObjectId(), registryObject);
if (hold)
hold(registryObject);
}
private void remove(RegistryObject registryObject, boolean release) {
cache.remove(registryObject.getObjectId());
if (release)
release(registryObject);
}
synchronized void remove(int id, boolean release) {
RegistryObject toRemove = (RegistryObject) cache.get(id);
if (fileOffsets != null)
fileOffsets.removeKey(id);
if (toRemove != null)
remove(toRemove, release);
}
private void hold(RegistryObject toHold) {
heldObjects.add(toHold);
}
private void release(RegistryObject toRelease) {
heldObjects.remove(toRelease);
}
@Override
public synchronized Object getObject(int id, byte type) {
return basicGetObject(id, type);
}
private Object basicGetObject(int id, byte type) {
Object result = cache.get(id);
if (result != null)
return result;
if (fromCache)
result = load(id, type);
if (result == null)
throw new InvalidRegistryObjectException();
cache.put(id, result);
return result;
}
// The current impementation of this method assumes that we don't cache dynamic
// extension. In this case all extensions not yet loaded (i.e. not in the memory cache)
// are "not dynamic" and we actually check memory objects to see if they are dynamic.
//
// If we decide to allow caching of dynamic objects, the implementation
// of this method would have to retrieved the object from disk and check
// its "dynamic" status. The problem is that id alone is not enough to get the object
// from the disk; object type is needed as well.
public boolean shouldPersist(int id) {
Object result = cache.get(id);
if (result != null)
return ((RegistryObject) result).shouldPersist();
return true;
}
@Override
public synchronized RegistryObject[] getObjects(int[] values, byte type) {
if (values.length == 0) {
switch (type) {
case EXTENSION_POINT :
return ExtensionPoint.EMPTY_ARRAY;
case EXTENSION :
return Extension.EMPTY_ARRAY;
case CONFIGURATION_ELEMENT :
case THIRDLEVEL_CONFIGURATION_ELEMENT :
return ConfigurationElement.EMPTY_ARRAY;
}
}
RegistryObject[] results = null;
switch (type) {
case EXTENSION_POINT :
results = new ExtensionPoint[values.length];
break;
case EXTENSION :
results = new Extension[values.length];
break;
case CONFIGURATION_ELEMENT :
case THIRDLEVEL_CONFIGURATION_ELEMENT :
results = new ConfigurationElement[values.length];
break;
}
for (int i = 0; i < values.length; i++) {
results[i] = (RegistryObject) basicGetObject(values[i], type);
}
return results;
}
synchronized ExtensionPoint getExtensionPointObject(String xptUniqueId) {
int id;
if ((id = extensionPoints.get(xptUniqueId)) == HashtableOfStringAndInt.MISSING_ELEMENT)
return null;
return (ExtensionPoint) getObject(id, EXTENSION_POINT);
}
@Override
public Handle getHandle(int id, byte type) {
switch (type) {
case EXTENSION_POINT :
return new ExtensionPointHandle(this, id);
case EXTENSION :
return new ExtensionHandle(this, id);
case CONFIGURATION_ELEMENT :
return new ConfigurationElementHandle(this, id);
case THIRDLEVEL_CONFIGURATION_ELEMENT :
default : //avoid compiler error, type should always be known
return new ThirdLevelConfigurationElementHandle(this, id);
}
}
@Override
public Handle[] getHandles(int[] ids, byte type) {
Handle[] results = null;
int nbrId = ids.length;
switch (type) {
case EXTENSION_POINT :
if (nbrId == 0)
return ExtensionPointHandle.EMPTY_ARRAY;
results = new ExtensionPointHandle[nbrId];
for (int i = 0; i < nbrId; i++) {
results[i] = new ExtensionPointHandle(this, ids[i]);
}
break;
case EXTENSION :
if (nbrId == 0)
return ExtensionHandle.EMPTY_ARRAY;
results = new ExtensionHandle[nbrId];
for (int i = 0; i < nbrId; i++) {
results[i] = new ExtensionHandle(this, ids[i]);
}
break;
case CONFIGURATION_ELEMENT :
if (nbrId == 0)
return ConfigurationElementHandle.EMPTY_ARRAY;
results = new ConfigurationElementHandle[nbrId];
for (int i = 0; i < nbrId; i++) {
results[i] = new ConfigurationElementHandle(this, ids[i]);
}
break;
case THIRDLEVEL_CONFIGURATION_ELEMENT :
if (nbrId == 0)
return ConfigurationElementHandle.EMPTY_ARRAY;
results = new ThirdLevelConfigurationElementHandle[nbrId];
for (int i = 0; i < nbrId; i++) {
results[i] = new ThirdLevelConfigurationElementHandle(this, ids[i]);
}
break;
}
return results;
}
synchronized ExtensionPointHandle[] getExtensionPointsHandles() {
return (ExtensionPointHandle[]) getHandles(extensionPoints.getValues(), EXTENSION_POINT);
}
synchronized ExtensionPointHandle getExtensionPointHandle(String xptUniqueId) {
int id = extensionPoints.get(xptUniqueId);
if (id == HashtableOfStringAndInt.MISSING_ELEMENT)
return null;
return (ExtensionPointHandle) getHandle(id, EXTENSION_POINT);
}
private Object load(int id, byte type) {
TableReader reader = registry.getTableReader();
if (fileOffsets == null)
return null;
int offset = fileOffsets.get(id);
if (offset == Integer.MIN_VALUE)
return null;
switch (type) {
case CONFIGURATION_ELEMENT :
return reader.loadConfigurationElement(offset);
case THIRDLEVEL_CONFIGURATION_ELEMENT :
return reader.loadThirdLevelConfigurationElements(offset, this);
case EXTENSION :
return reader.loadExtension(offset);
case EXTENSION_POINT :
default : //avoid compile errors. type must always be known
return reader.loadExtensionPointTree(offset, this);
}
}
synchronized int[] getExtensionsFrom(String contributorId) {
KeyedElement tmp = newContributions.getByKey(contributorId);
if (tmp == null)
tmp = getFormerContributions().getByKey(contributorId);
if (tmp == null)
return EMPTY_INT_ARRAY;
return ((Contribution) tmp).getExtensions();
}
synchronized boolean addExtensionPoint(ExtensionPoint currentExtPoint, boolean hold) {
String uniqueId = currentExtPoint.getUniqueIdentifier();
if (extensionPoints.get(uniqueId) != HashtableOfStringAndInt.MISSING_ELEMENT)
return false;
add(currentExtPoint, hold);
extensionPoints.put(uniqueId, currentExtPoint.getObjectId());
return true;
}
synchronized void removeExtensionPoint(String extensionPointId) {
int pointId = extensionPoints.removeKey(extensionPointId);
if (pointId == HashtableOfStringAndInt.MISSING_ELEMENT)
return;
remove(pointId, true);
}
public boolean isDirty() {
return isDirty;
}
public void markDirty() {
isDirty = true;
}
synchronized void removeContribution(Object contributorId) {
boolean removed = newContributions.removeByKey(contributorId);
if (removed == false) {
removed = getFormerContributions().removeByKey(contributorId);
if (removed)
formerContributions = getFormerContributions(); //This forces the removed namespace to stay around, so we do not forget about removed namespaces
}
if (removed) {
isDirty = true;
return;
}
}
@SuppressWarnings("unchecked")
private Map getOrphans() {
Object result;
if (orphanExtensions == null && !fromCache) {
result = new HashMap<>();
orphanExtensions = result;
} else if (orphanExtensions == null || (result = ((orphanExtensions instanceof SoftReference) ? ((SoftReference) orphanExtensions).get() : orphanExtensions)) == null) {
result = registry.getTableReader().loadOrphans();
orphanExtensions = new SoftReference<>(result);
}
return (HashMap) result;
}
void addOrphans(String extensionPoint, int[] extensions) {
Map orphans = getOrphans();
int[] existingOrphanExtensions = orphans.get(extensionPoint);
if (existingOrphanExtensions != null) {
// just add
int[] newOrphanExtensions = new int[existingOrphanExtensions.length + extensions.length];
System.arraycopy(existingOrphanExtensions, 0, newOrphanExtensions, 0, existingOrphanExtensions.length);
System.arraycopy(extensions, 0, newOrphanExtensions, existingOrphanExtensions.length, extensions.length);
orphans.put(extensionPoint, newOrphanExtensions);
} else {
// otherwise this is the first one
orphans.put(extensionPoint, extensions);
}
markOrphansHasDirty(orphans);
}
void markOrphansHasDirty(Map orphans) {
orphanExtensions = orphans;
}
void addOrphan(String extensionPoint, int extension) {
Map orphans = getOrphans();
int[] existingOrphanExtensions = orphans.get(extensionPoint);
if (existingOrphanExtensions != null) {
// just add
int[] newOrphanExtensions = new int[existingOrphanExtensions.length + 1];
System.arraycopy(existingOrphanExtensions, 0, newOrphanExtensions, 0, existingOrphanExtensions.length);
newOrphanExtensions[existingOrphanExtensions.length] = extension;
orphans.put(extensionPoint, newOrphanExtensions);
} else {
// otherwise this is the first one
orphans.put(extensionPoint, new int[] {extension});
}
markOrphansHasDirty(orphans);
}
int[] removeOrphans(String extensionPoint) {
Map orphans = getOrphans();
int[] existingOrphanExtensions = orphans.remove(extensionPoint);
if (existingOrphanExtensions != null) {
markOrphansHasDirty(orphans);
}
return existingOrphanExtensions;
}
void removeOrphan(String extensionPoint, int extension) {
Map orphans = getOrphans();
int[] existingOrphanExtensions = orphans.get(extensionPoint);
if (existingOrphanExtensions == null)
return;
markOrphansHasDirty(orphans);
int newSize = existingOrphanExtensions.length - 1;
if (newSize == 0) {
orphans.remove(extensionPoint);
return;
}
int[] newOrphanExtensions = new int[existingOrphanExtensions.length - 1];
for (int i = 0, j = 0; i < existingOrphanExtensions.length; i++)
if (extension != existingOrphanExtensions[i])
newOrphanExtensions[j++] = existingOrphanExtensions[i];
orphans.put(extensionPoint, newOrphanExtensions);
return;
}
//This method is only used by the writer to reach in
Map getOrphanExtensions() {
return getOrphans();
}
// This method is only used by the writer to reach in
int getNextId() {
return nextId;
}
// This method is only used by the writer to reach in
HashtableOfStringAndInt getExtensionPoints() {
return extensionPoints;
}
// This method is only used by the writer to reach in
KeyedHashSet[] getContributions() {
return new KeyedHashSet[] {newContributions, getFormerContributions()};
}
// This method is used internally and by the writer to reach in. Notice that it doesn't
// return contributors marked as removed.
HashMap getContributors() {
if (contributors == null) {
if (fromCache == false)
contributors = new HashMap<>();
else
contributors = registry.getTableReader().loadContributors();
}
return contributors;
}
synchronized IContributor[] getContributorsSync() {
Collection contributorValues = getContributors().values();
return contributorValues.toArray(new IContributor[contributorValues.size()]);
}
synchronized RegistryContributor getContributor(String id) {
RegistryContributor contributor = getContributors().get(id);
if (contributor != null)
return contributor;
// check if we have it among removed contributors - potentially
// notification of removals might be processed after the contributor
// marked as removed:
if (removedContributors != null)
return removedContributors.get(id);
return null;
}
// only adds a contributor if it is not already present in the table
synchronized void addContributor(RegistryContributor newContributor) {
String key = newContributor.getActualId();
if (!getContributors().containsKey(key)) {
isDirty = true;
if (removedContributors != null)
removedContributors.remove(key);
getContributors().put(key, newContributor);
}
}
synchronized void removeContributor(String id) {
isDirty = true;
RegistryContributor removed = getContributors().remove(id);
if (removed != null) {
if (removedContributors == null)
removedContributors = new HashMap<>();
removedContributors.put(id, removed);
}
}
KeyedHashSet getNamespacesIndex() {
if (namespacesIndex == null) {
if (fromCache == false)
namespacesIndex = new KeyedHashSet(0);
else
namespacesIndex = registry.getTableReader().loadNamespaces();
}
return namespacesIndex;
}
// Find or create required index element
private RegistryIndexElement getNamespaceIndex(String namespaceName) {
RegistryIndexElement indexElement = (RegistryIndexElement) getNamespacesIndex().getByKey(namespaceName);
if (indexElement == null) {
indexElement = new RegistryIndexElement(namespaceName);
namespacesIndex.add(indexElement);
}
return indexElement;
}
/**
* Collect all the objects that are removed by this operation and store
* them in a IObjectManager so that they can be accessed from the appropriate
* deltas but not from the registry.
*/
synchronized Map getAssociatedObjects(String contributionId) {
//Collect all the objects associated with this contribution
int[] xpts = getExtensionPointsFrom(contributionId);
int[] exts = getExtensionsFrom(contributionId);
Map actualObjects = new HashMap<>(xpts.length + exts.length);
for (int ext : exts) {
Extension tmp = (Extension) basicGetObject(ext, RegistryObjectManager.EXTENSION);
actualObjects.put(Integer.valueOf(ext), tmp);
collectChildren(tmp, 0, actualObjects);
}
for (int xpt2 : xpts) {
ExtensionPoint xpt = (ExtensionPoint) basicGetObject(xpt2, RegistryObjectManager.EXTENSION_POINT);
actualObjects.put(Integer.valueOf(xpt2), xpt);
}
return actualObjects;
}
/**
* Adds elements to be removed along with the registry object.
*/
synchronized void addAssociatedObjects(Map map, RegistryObject registryObject) {
collectChildren(registryObject, 0, map);
}
/**
* Add to the set of the objects all extensions and extension points that
* could be navigated to from the objects in the set.
*/
synchronized void addNavigableObjects(Map associatedObjects) {
Map result = new HashMap<>();
for (RegistryObject object : associatedObjects.values()) {
if (object instanceof Extension) {
// add extension point
ExtensionPoint extPoint = getExtensionPointObject(((Extension) object).getExtensionPointIdentifier());
if (extPoint == null) // already removed?
continue;
Integer extPointIndex = Integer.valueOf(extPoint.getKeyHashCode());
if (!associatedObjects.containsKey(extPointIndex))
result.put(Integer.valueOf(extPoint.getKeyHashCode()), extPoint);
// add all extensions for the extension point
for (int childId : extPoint.getRawChildren()) {
Extension tmp = (Extension) basicGetObject(childId, RegistryObjectManager.EXTENSION);
if (tmp == null) // already removed
continue;
Integer extensionIndex = Integer.valueOf(childId);
if (!associatedObjects.containsKey(extensionIndex)) {
result.put(extensionIndex, tmp);
collectChildren(tmp, 0, result);
}
}
} else if (object instanceof ExtensionPoint) {
// by now extensions of this extension point have been marked as orphans
Map orphans = getOrphans();
String name = ((ExtensionPoint) object).getUniqueIdentifier();
int[] extensions = orphans.get(name);
if (extensions != null) {
for (int orphanId : extensions) {
Extension tmp = (Extension) basicGetObject(orphanId, RegistryObjectManager.EXTENSION);
if (tmp == null) // already removed
continue;
Integer extensionIndex = Integer.valueOf(orphanId);
if (!associatedObjects.containsKey(extensionIndex)) {
result.put(extensionIndex, tmp);
collectChildren(tmp, 0, result);
}
}
}
}
}
associatedObjects.putAll(result);
}
synchronized void removeObjects(Map associatedObjects) {
//Remove the objects from the main object manager so they can no longer be accessed.
for (Object registryObject : associatedObjects.values()) {
RegistryObject toRemove = (RegistryObject) registryObject;
remove((toRemove).getObjectId(), true);
if (toRemove instanceof ExtensionPoint)
removeExtensionPoint(((ExtensionPoint) toRemove).getUniqueIdentifier());
}
}
IObjectManager createDelegatingObjectManager(Map object) {
return new TemporaryObjectManager(object, this);
}
private void collectChildren(RegistryObject ce, int level, Map collector) {
ConfigurationElement[] children = (ConfigurationElement[]) getObjects(ce.getRawChildren(), level == 0 || ce.noExtraData() ? RegistryObjectManager.CONFIGURATION_ELEMENT : RegistryObjectManager.THIRDLEVEL_CONFIGURATION_ELEMENT);
for (ConfigurationElement child : children) {
collector.put(Integer.valueOf(child.getObjectId()), child);
collectChildren(child, level + 1, collector);
}
}
@Override
public void close() {
//do nothing.
}
public ExtensionRegistry getRegistry() {
return registry;
}
// Called from a synchronized method only
private boolean unlinkChildFromContributions(KeyedElement[] contributions, int id) {
for (KeyedElement contribution : contributions) {
Contribution candidate = (Contribution) contribution;
if (candidate == null)
continue;
if (candidate.hasChild(id)) {
candidate.unlinkChild(id);
if (candidate.isEmpty())
removeContribution(candidate.getContributorId());
return true;
}
}
return false;
}
synchronized boolean unlinkChildFromContributions(int id) {
if (unlinkChildFromContributions(newContributions.elements, id))
return true;
return unlinkChildFromContributions(getFormerContributions().elements, id);
}
synchronized public ExtensionPointHandle[] getExtensionPointsFromNamespace(String namespaceName) {
RegistryIndexElement indexElement = getNamespaceIndex(namespaceName);
int[] namespaceExtensionPoints = indexElement.getExtensionPoints();
return (ExtensionPointHandle[]) getHandles(namespaceExtensionPoints, EXTENSION_POINT);
}
// This method filters out extensions with no extension point
synchronized public ExtensionHandle[] getExtensionsFromNamespace(String namespaceName) {
RegistryIndexElement indexElement = getNamespaceIndex(namespaceName);
int[] namespaceExtensions = indexElement.getExtensions();
// filter extensions with no extension point (orphan extensions)
List tmp = new ArrayList<>();
Extension[] exts = (Extension[]) getObjects(namespaceExtensions, EXTENSION);
for (Extension ext : exts) {
if (getExtensionPointObject(ext.getExtensionPointIdentifier()) != null) {
tmp.add(getHandle(ext.getObjectId(), EXTENSION));
}
}
if (tmp.size() == 0)
return EMPTY_EXTENSIONS_ARRAY;
ExtensionHandle[] result = new ExtensionHandle[tmp.size()];
return tmp.toArray(result);
}
public ExtensionHandle[] getExtensionsFromContributor(String contributorId) {
int[] ids = getExtensionsFrom(contributorId); // never null
return (ExtensionHandle[]) getHandles(ids, RegistryObjectManager.EXTENSION);
}
public ExtensionPointHandle[] getExtensionPointsFromContributor(String contributorId) {
int[] ids = getExtensionPointsFrom(contributorId); // never null
return (ExtensionPointHandle[]) getHandles(ids, RegistryObjectManager.EXTENSION_POINT);
}
}