package org.eclipse.core.internal.registry;
import java.io.*;
import java.lang.reflect.Array;
import java.util.*;
import javax.xml.parsers.ParserConfigurationException;
import org.eclipse.core.internal.registry.spi.ConfigurationElementAttribute;
import org.eclipse.core.internal.registry.spi.ConfigurationElementDescription;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.spi.*;
import org.eclipse.osgi.storagemanager.StorageManager;
import org.eclipse.osgi.util.NLS;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class ExtensionRegistry implements IExtensionRegistry, IDynamicExtensionRegistry {
protected class ListenerInfo {
public String filter;
public EventListener listener;
public ListenerInfo(EventListener listener, String filter) {
this.listener = listener;
this.filter = filter;
}
@Override
public boolean equals(Object another) {
return another instanceof ListenerInfo && ((ListenerInfo) another).listener == this.listener;
}
@Override
public int hashCode() {
return listener == null ? 0 : listener.hashCode();
}
}
private final ReadWriteMonitor access = new ReadWriteMonitor();
private transient Map<String, Object> deltas = new HashMap<>(11);
protected StorageManager cacheStorageManager;
private transient ListenerList<ListenerInfo> listeners = new ListenerList<>();
private RegistryObjectManager registryObjects = null;
protected TableReader theTableReader = new TableReader(this);
private final Object masterToken;
private final Object userToken;
protected RegistryStrategy strategy;
private final RegistryTimestamp aggregatedTimestamp = new RegistryTimestamp();
private CombinedEventDelta eventDelta = null;
private final static String notNamespace = "";
private final boolean isMultiLanguage;
private boolean mlErrorLogged = false;
public RegistryObjectManager getObjectManager() {
return registryObjects;
}
protected void setFileManager(File cacheBase, boolean isCacheReadOnly) {
if (cacheStorageManager != null)
cacheStorageManager.close();
if (cacheBase != null) {
cacheStorageManager = new StorageManager(cacheBase, isCacheReadOnly ? "none" : null, isCacheReadOnly);
try {
cacheStorageManager.open(!isCacheReadOnly);
} catch (IOException e) {
}
}
}
private void add(Contribution element) {
access.enterWrite();
try {
eventDelta = CombinedEventDelta.recordAddition();
basicAdd(element, true);
fireRegistryChangeEvent();
eventDelta = null;
} finally {
access.exitWrite();
}
}
static Object concatArrays(Object a, Object b) {
Object[] result = (Object[]) Array.newInstance(a.getClass().getComponentType(), Array.getLength(a) + Array.getLength(b));
System.arraycopy(a, 0, result, 0, Array.getLength(a));
System.arraycopy(b, 0, result, Array.getLength(a), Array.getLength(b));
return result;
}
private String addExtension(int extension) {
Extension addedExtension = (Extension) registryObjects.getObject(extension, RegistryObjectManager.EXTENSION);
String extensionPointToAddTo = addedExtension.getExtensionPointIdentifier();
ExtensionPoint extPoint = registryObjects.getExtensionPointObject(extensionPointToAddTo);
if (extPoint == null) {
registryObjects.addOrphan(extensionPointToAddTo, extension);
return null;
}
int[] newExtensions;
int[] existingExtensions = extPoint.getRawChildren();
newExtensions = new int[existingExtensions.length + 1];
System.arraycopy(existingExtensions, 0, newExtensions, 0, existingExtensions.length);
newExtensions[newExtensions.length - 1] = extension;
link(extPoint, newExtensions);
if (eventDelta != null)
eventDelta.rememberExtension(extPoint, extension);
return recordChange(extPoint, extension, IExtensionDelta.ADDED);
}
private String addExtensionPoint(int extPoint) {
ExtensionPoint extensionPoint = (ExtensionPoint) registryObjects.getObject(extPoint, RegistryObjectManager.EXTENSION_POINT);
if (eventDelta != null)
eventDelta.rememberExtensionPoint(extensionPoint);
int[] orphans = registryObjects.removeOrphans(extensionPoint.getUniqueIdentifier());
if (orphans == null)
return null;
link(extensionPoint, orphans);
if (eventDelta != null)
eventDelta.rememberExtensions(extensionPoint, orphans);
return recordChange(extensionPoint, orphans, IExtensionDelta.ADDED);
}
private Set<String> addExtensionsAndExtensionPoints(Contribution element) {
Set<String> affectedNamespaces = new HashSet<>();
int[] extPoints = element.getExtensionPoints();
for (int i = 0; i < extPoints.length; i++) {
String namespace = this.addExtensionPoint(extPoints[i]);
if (namespace != null)
affectedNamespaces.add(namespace);
}
int[] extensions = element.getExtensions();
for (int i = 0; i < extensions.length; i++) {
String namespace = this.addExtension(extensions[i]);
if (namespace != null)
affectedNamespaces.add(namespace);
}
return affectedNamespaces;
}
@Override
public void addListener(IRegistryEventListener listener) {
addListenerInternal(listener, null);
}
@Override
public void addListener(IRegistryEventListener listener, String extensionPointId) {
addListenerInternal(listener, extensionPointId);
}
private void addListenerInternal(EventListener listener, String filter) {
synchronized (listeners) {
listeners.add(new ListenerInfo(listener, filter));
}
}
@Override
public void addRegistryChangeListener(IRegistryChangeListener listener) {
addListenerInternal(listener, null);
}
@Override
public void addRegistryChangeListener(IRegistryChangeListener listener, String filter) {
addListenerInternal(listener, filter);
}
private void basicAdd(Contribution element, boolean link) {
registryObjects.addContribution(element);
if (!link)
return;
Set<String> affectedNamespaces = addExtensionsAndExtensionPoints(element);
setObjectManagers(affectedNamespaces, registryObjects.createDelegatingObjectManager(registryObjects.getAssociatedObjects(element.getContributorId())));
}
private void setObjectManagers(Set<String> affectedNamespaces, IObjectManager manager) {
for (Iterator<String> iter = affectedNamespaces.iterator(); iter.hasNext();) {
getDelta(iter.next()).setObjectManager(manager);
}
if (eventDelta != null)
eventDelta.setObjectManager(manager);
}
private void basicRemove(String contributorId) {
Set<String> affectedNamespaces = removeExtensionsAndExtensionPoints(contributorId);
Map<Integer, RegistryObject> associatedObjects = registryObjects.getAssociatedObjects(contributorId);
registryObjects.removeObjects(associatedObjects);
registryObjects.addNavigableObjects(associatedObjects);
setObjectManagers(affectedNamespaces, registryObjects.createDelegatingObjectManager(associatedObjects));
registryObjects.removeContribution(contributorId);
registryObjects.removeContributor(contributorId);
}
void enterRead() {
access.enterRead();
}
void exitRead() {
access.exitRead();
}
private void fireRegistryChangeEvent() {
deltas.put(notNamespace, eventDelta);
if (listeners.isEmpty()) {
deltas.clear();
return;
}
Object[] tmpListeners = listeners.getListeners();
Map<String, Object> tmpDeltas = new HashMap<>(this.deltas);
deltas.clear();
strategy.scheduleChangeEvent(tmpListeners, tmpDeltas, this);
}
@Override
public IConfigurationElement[] getConfigurationElementsFor(String extensionPointId) {
int lastdot = extensionPointId.lastIndexOf('.');
if (lastdot == -1)
return new IConfigurationElement[0];
return getConfigurationElementsFor(extensionPointId.substring(0, lastdot), extensionPointId.substring(lastdot + 1));
}
@Override
public IConfigurationElement[] getConfigurationElementsFor(String pluginId, String extensionPointSimpleId) {
IExtensionPoint extPoint = this.getExtensionPoint(pluginId, extensionPointSimpleId);
if (extPoint == null)
return new IConfigurationElement[0];
return extPoint.getConfigurationElements();
}
@Override
public IConfigurationElement[] getConfigurationElementsFor(String pluginId, String extensionPointName, String extensionId) {
IExtension extension = this.getExtension(pluginId, extensionPointName, extensionId);
if (extension == null)
return new IConfigurationElement[0];
return extension.getConfigurationElements();
}
private RegistryDelta getDelta(String namespace) {
RegistryDelta existingDelta = (RegistryDelta) deltas.get(namespace);
if (existingDelta != null)
return existingDelta;
RegistryDelta delta = new RegistryDelta();
deltas.put(namespace, delta);
return delta;
}
@Override
public IExtension getExtension(String extensionId) {
if (extensionId == null)
return null;
int lastdot = extensionId.lastIndexOf('.');
if (lastdot == -1)
return null;
String namespace = extensionId.substring(0, lastdot);
ExtensionHandle[] extensions;
access.enterRead();
try {
extensions = registryObjects.getExtensionsFromNamespace(namespace);
} finally {
access.exitRead();
}
for (int i = 0; i < extensions.length; i++) {
ExtensionHandle suspect = extensions[i];
if (extensionId.equals(suspect.getUniqueIdentifier()))
return suspect;
}
return null;
}
@Override
public IExtension getExtension(String extensionPointId, String extensionId) {
int lastdot = extensionPointId.lastIndexOf('.');
if (lastdot == -1)
return null;
return getExtension(extensionPointId.substring(0, lastdot), extensionPointId.substring(lastdot + 1), extensionId);
}
@Override
public IExtension getExtension(String pluginId, String extensionPointName, String extensionId) {
IExtensionPoint extPoint = getExtensionPoint(pluginId, extensionPointName);
if (extPoint != null)
return extPoint.getExtension(extensionId);
return null;
}
@Override
public IExtensionPoint getExtensionPoint(String xptUniqueId) {
access.enterRead();
try {
return registryObjects.getExtensionPointHandle(xptUniqueId);
} finally {
access.exitRead();
}
}
@Override
public IExtensionPoint getExtensionPoint(String elementName, String xpt) {
access.enterRead();
try {
return registryObjects.getExtensionPointHandle(elementName + '.' + xpt);
} finally {
access.exitRead();
}
}
@Override
public IExtensionPoint[] getExtensionPoints() {
access.enterRead();
try {
return registryObjects.getExtensionPointsHandles();
} finally {
access.exitRead();
}
}
@Override
public IExtensionPoint[] getExtensionPoints(String namespaceName) {
access.enterRead();
try {
return registryObjects.getExtensionPointsFromNamespace(namespaceName);
} finally {
access.exitRead();
}
}
@Override
public IExtension[] getExtensions(String namespaceName) {
access.enterRead();
try {
return registryObjects.getExtensionsFromNamespace(namespaceName);
} finally {
access.exitRead();
}
}
@Override
public IExtension[] getExtensions(IContributor contributor) {
if (!(contributor instanceof RegistryContributor))
throw new IllegalArgumentException();
String contributorId = ((RegistryContributor) contributor).getActualId();
access.enterRead();
try {
return registryObjects.getExtensionsFromContributor(contributorId);
} finally {
access.exitRead();
}
}
@Override
public IExtensionPoint[] getExtensionPoints(IContributor contributor) {
if (!(contributor instanceof RegistryContributor))
throw new IllegalArgumentException();
String contributorId = ((RegistryContributor) contributor).getActualId();
access.enterRead();
try {
return registryObjects.getExtensionPointsFromContributor(contributorId);
} finally {
access.exitRead();
}
}
@Override
public String[] getNamespaces() {
access.enterRead();
try {
KeyedElement[] namespaceElements = registryObjects.getNamespacesIndex().elements();
String[] namespaceNames = new String[namespaceElements.length];
for (int i = 0; i < namespaceElements.length; i++) {
namespaceNames[i] = (String) ((RegistryIndexElement) namespaceElements[i]).getKey();
}
return namespaceNames;
} finally {
access.exitRead();
}
}
@Override
public boolean hasContributor(IContributor contributor) {
if (!(contributor instanceof RegistryContributor))
throw new IllegalArgumentException();
String contributorId = ((RegistryContributor) contributor).getActualId();
return hasContributor(contributorId);
}
public boolean hasContributor(String contributorId) {
access.enterRead();
try {
return registryObjects.hasContribution(contributorId);
} finally {
access.exitRead();
}
}
private void link(ExtensionPoint extPoint, int[] extensions) {
extPoint.setRawChildren(extensions);
registryObjects.add(extPoint, true);
}
private String recordChange(ExtensionPoint extPoint, int extension, int kind) {
if (listeners.isEmpty())
return null;
ExtensionDelta extensionDelta = new ExtensionDelta();
extensionDelta.setExtension(extension);
extensionDelta.setExtensionPoint(extPoint.getObjectId());
extensionDelta.setKind(kind);
getDelta(extPoint.getNamespace()).addExtensionDelta(extensionDelta);
return extPoint.getNamespace();
}
private String recordChange(ExtensionPoint extPoint, int[] extensions, int kind) {
if (listeners.isEmpty())
return null;
String namespace = extPoint.getNamespace();
if (extensions == null || extensions.length == 0)
return namespace;
RegistryDelta pluginDelta = getDelta(extPoint.getNamespace());
for (int i = 0; i < extensions.length; i++) {
ExtensionDelta extensionDelta = new ExtensionDelta();
extensionDelta.setExtension(extensions[i]);
extensionDelta.setExtensionPoint(extPoint.getObjectId());
extensionDelta.setKind(kind);
pluginDelta.addExtensionDelta(extensionDelta);
}
return namespace;
}
public void remove(String removedContributorId, long timestamp) {
remove(removedContributorId);
if (timestamp != 0)
aggregatedTimestamp.remove(timestamp);
}
@Override
public void removeContributor(IContributor contributor, Object key) {
if (!(contributor instanceof RegistryContributor))
throw new IllegalArgumentException();
if (!checkReadWriteAccess(key, true))
throw new IllegalArgumentException("Unauthorized access to the ExtensionRegistry.removeContributor() method. Check if proper access token is supplied.");
String contributorId = ((RegistryContributor) contributor).getActualId();
remove(contributorId);
}
public void remove(String removedContributorId) {
access.enterWrite();
try {
eventDelta = CombinedEventDelta.recordRemoval();
basicRemove(removedContributorId);
fireRegistryChangeEvent();
eventDelta = null;
} finally {
access.exitWrite();
}
}
private String removeExtension(int extensionId) {
Extension extension = (Extension) registryObjects.getObject(extensionId, RegistryObjectManager.EXTENSION);
registryObjects.removeExtensionFromNamespaceIndex(extensionId, extension.getNamespaceIdentifier());
String xptName = extension.getExtensionPointIdentifier();
ExtensionPoint extPoint = registryObjects.getExtensionPointObject(xptName);
if (extPoint == null) {
registryObjects.removeOrphan(xptName, extensionId);
return null;
}
int[] existingExtensions = extPoint.getRawChildren();
int[] newExtensions = RegistryObjectManager.EMPTY_INT_ARRAY;
if (existingExtensions.length > 1) {
if (existingExtensions.length == 1)
newExtensions = RegistryObjectManager.EMPTY_INT_ARRAY;
newExtensions = new int[existingExtensions.length - 1];
for (int i = 0, j = 0; i < existingExtensions.length; i++)
if (existingExtensions[i] != extension.getObjectId())
newExtensions[j++] = existingExtensions[i];
}
link(extPoint, newExtensions);
if (eventDelta != null)
eventDelta.rememberExtension(extPoint, extensionId);
return recordChange(extPoint, extension.getObjectId(), IExtensionDelta.REMOVED);
}
private String removeExtensionPoint(int extPoint) {
ExtensionPoint extensionPoint = (ExtensionPoint) registryObjects.getObject(extPoint, RegistryObjectManager.EXTENSION_POINT);
registryObjects.removeExtensionPointFromNamespaceIndex(extPoint, extensionPoint.getNamespace());
int[] existingExtensions = extensionPoint.getRawChildren();
if (existingExtensions != null && existingExtensions.length != 0) {
registryObjects.addOrphans(extensionPoint.getUniqueIdentifier(), existingExtensions);
link(extensionPoint, RegistryObjectManager.EMPTY_INT_ARRAY);
}
if (eventDelta != null) {
eventDelta.rememberExtensionPoint(extensionPoint);
eventDelta.rememberExtensions(extensionPoint, existingExtensions);
}
return recordChange(extensionPoint, existingExtensions, IExtensionDelta.REMOVED);
}
private Set<String> removeExtensionsAndExtensionPoints(String contributorId) {
Set<String> affectedNamespaces = new HashSet<>();
int[] extensions = registryObjects.getExtensionsFrom(contributorId);
for (int i = 0; i < extensions.length; i++) {
String namespace = this.removeExtension(extensions[i]);
if (namespace != null)
affectedNamespaces.add(namespace);
}
int[] extPoints = registryObjects.getExtensionPointsFrom(contributorId);
for (int i = 0; i < extPoints.length; i++) {
String namespace = this.removeExtensionPoint(extPoints[i]);
if (namespace != null)
affectedNamespaces.add(namespace);
}
return affectedNamespaces;
}
@Override
public void removeRegistryChangeListener(IRegistryChangeListener listener) {
synchronized (listeners) {
listeners.remove(new ListenerInfo(listener, null));
}
}
@Override
public void removeListener(IRegistryEventListener listener) {
synchronized (listeners) {
listeners.remove(new ListenerInfo(listener, null));
}
}
public ExtensionRegistry(RegistryStrategy registryStrategy, Object masterToken, Object userToken) {
isMultiLanguage = "true".equals(RegistryProperties.getProperty(IRegistryConstants.PROP_MULTI_LANGUAGE));
if (registryStrategy != null)
strategy = registryStrategy;
else
strategy = new RegistryStrategy(null, null);
this.masterToken = masterToken;
this.userToken = userToken;
registryObjects = new RegistryObjectManager(this);
boolean isRegistryFilledFromCache = false;
if (strategy.cacheUse()) {
long start = 0;
if (debug())
start = System.currentTimeMillis();
if (checkCache()) {
try {
theTableReader.setTableFile(cacheStorageManager.lookup(TableReader.TABLE, false));
theTableReader.setExtraDataFile(cacheStorageManager.lookup(TableReader.EXTRA, false));
theTableReader.setMainDataFile(cacheStorageManager.lookup(TableReader.MAIN, false));
theTableReader.setContributionsFile(cacheStorageManager.lookup(TableReader.CONTRIBUTIONS, false));
theTableReader.setContributorsFile(cacheStorageManager.lookup(TableReader.CONTRIBUTORS, false));
theTableReader.setNamespacesFile(cacheStorageManager.lookup(TableReader.NAMESPACES, false));
theTableReader.setOrphansFile(cacheStorageManager.lookup(TableReader.ORPHANS, false));
long timestamp = strategy.getContributionsTimestamp();
isRegistryFilledFromCache = registryObjects.init(timestamp);
if (isRegistryFilledFromCache)
aggregatedTimestamp.set(timestamp);
} catch (IOException e) {
isRegistryFilledFromCache = false;
clearRegistryCache();
log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, 0, RegistryMessages.registry_bad_cache, e));
}
}
if (!isRegistryFilledFromCache) {
for (int index = 0; index < strategy.getLocationsLength(); index++) {
if (!strategy.isCacheReadOnly(index)) {
setFileManager(strategy.getStorage(index), false);
break;
}
}
}
if (debug() && isRegistryFilledFromCache)
System.out.println("Reading registry cache: " + (System.currentTimeMillis() - start));
if (debug()) {
if (!isRegistryFilledFromCache)
System.out.println("Reloading registry from manifest files...");
else
System.out.println("Using registry cache...");
}
}
if (debugEvents())
addRegistryChangeListener(System.out::println);
strategy.onStart(this);
strategy.onStart(this, isRegistryFilledFromCache);
}
@Override
public void stop(Object key) {
if (masterToken != null && masterToken != key) {
throw new IllegalArgumentException("Unauthorized access to the ExtensionRegistry.stop() method. Check if proper access token is supplied.");
}
strategy.onStop(this);
stopChangeEventScheduler();
if (cacheStorageManager == null)
return;
if (!registryObjects.isDirty() || cacheStorageManager.isReadOnly()) {
cacheStorageManager.close();
theTableReader.close();
return;
}
File tableFile = null;
File mainFile = null;
File extraFile = null;
File contributionsFile = null;
File contributorsFile = null;
File namespacesFile = null;
File orphansFile = null;
TableWriter theTableWriter = new TableWriter(this);
try {
cacheStorageManager.lookup(TableReader.TABLE, true);
cacheStorageManager.lookup(TableReader.MAIN, true);
cacheStorageManager.lookup(TableReader.EXTRA, true);
cacheStorageManager.lookup(TableReader.CONTRIBUTIONS, true);
cacheStorageManager.lookup(TableReader.CONTRIBUTORS, true);
cacheStorageManager.lookup(TableReader.NAMESPACES, true);
cacheStorageManager.lookup(TableReader.ORPHANS, true);
tableFile = File.createTempFile(TableReader.TABLE, ".new", cacheStorageManager.getBase());
mainFile = File.createTempFile(TableReader.MAIN, ".new", cacheStorageManager.getBase());
extraFile = File.createTempFile(TableReader.EXTRA, ".new", cacheStorageManager.getBase());
contributionsFile = File.createTempFile(TableReader.CONTRIBUTIONS, ".new", cacheStorageManager.getBase());
contributorsFile = File.createTempFile(TableReader.CONTRIBUTORS, ".new", cacheStorageManager.getBase());
namespacesFile = File.createTempFile(TableReader.NAMESPACES, ".new", cacheStorageManager.getBase());
orphansFile = File.createTempFile(TableReader.ORPHANS, ".new", cacheStorageManager.getBase());
theTableWriter.setTableFile(tableFile);
theTableWriter.setExtraDataFile(extraFile);
theTableWriter.setMainDataFile(mainFile);
theTableWriter.setContributionsFile(contributionsFile);
theTableWriter.setContributorsFile(contributorsFile);
theTableWriter.setNamespacesFile(namespacesFile);
theTableWriter.setOrphansFile(orphansFile);
} catch (IOException e) {
cacheStorageManager.close();
return;
}
try {
long timestamp;
if (aggregatedTimestamp.isModifed())
timestamp = aggregatedTimestamp.getContentsTimestamp();
else
timestamp = strategy.getContributionsTimestamp();
if (theTableWriter.saveCache(registryObjects, timestamp))
cacheStorageManager.update(new String[] {TableReader.TABLE, TableReader.MAIN, TableReader.EXTRA, TableReader.CONTRIBUTIONS, TableReader.CONTRIBUTORS, TableReader.NAMESPACES, TableReader.ORPHANS}, new String[] {tableFile.getName(), mainFile.getName(), extraFile.getName(), contributionsFile.getName(), contributorsFile.getName(), namespacesFile.getName(), orphansFile.getName()});
} catch (IOException e) {
}
theTableReader.close();
cacheStorageManager.close();
}
public void clearRegistryCache() {
String[] keys = new String[] {TableReader.TABLE, TableReader.MAIN, TableReader.EXTRA, TableReader.CONTRIBUTIONS, TableReader.ORPHANS};
for (int i = 0; i < keys.length; i++)
try {
cacheStorageManager.remove(keys[i]);
} catch (IOException e) {
log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, IStatus.ERROR, RegistryMessages.meta_registryCacheReadProblems, e));
}
aggregatedTimestamp.reset();
}
protected RegistryObjectFactory theRegistryObjectFactory = null;
protected void setElementFactory() {
if (isMultiLanguage)
theRegistryObjectFactory = new RegistryObjectFactoryMulti(this);
else
theRegistryObjectFactory = new RegistryObjectFactory(this);
}
public RegistryObjectFactory getElementFactory() {
if (theRegistryObjectFactory == null)
setElementFactory();
return theRegistryObjectFactory;
}
TableReader getTableReader() {
return theTableReader;
}
public void log(IStatus status) {
strategy.log(status);
}
public String translate(String key, ResourceBundle resources) {
if (isMultiLanguage)
return key;
return strategy.translate(key, resources);
}
public boolean debug() {
return strategy.debug();
}
public boolean debugEvents() {
return strategy.debugRegistryEvents();
}
public boolean useLazyCacheLoading() {
return strategy.cacheLazyLoading();
}
public long computeState() {
return strategy.getContainerTimestamp();
}
protected boolean checkCache() {
for (int index = 0; index < strategy.getLocationsLength(); index++) {
File possibleCacheLocation = strategy.getStorage(index);
if (possibleCacheLocation == null)
break;
setFileManager(possibleCacheLocation, strategy.isCacheReadOnly(index));
if (cacheStorageManager != null) {
File cacheFile = null;
try {
cacheFile = cacheStorageManager.lookup(TableReader.getTestFileName(), false);
} catch (IOException e) {
}
if (cacheFile != null && cacheFile.isFile())
return true;
}
}
return false;
}
public Object createExecutableExtension(RegistryContributor defaultContributor, String className, String requestedContributorName) throws CoreException {
return strategy.createExecutableExtension(defaultContributor, className, requestedContributorName);
}
public IStatus processChangeEvent(Object[] listenerInfos, final Map<String, ?> scheduledDeltas) {
final CombinedEventDelta extendedDelta = (CombinedEventDelta) scheduledDeltas.remove(notNamespace);
final MultiStatus result = new MultiStatus(RegistryMessages.OWNER_NAME, IStatus.OK, RegistryMessages.plugin_eventListenerError, null);
for (int i = 0; i < listenerInfos.length; i++) {
final ListenerInfo listenerInfo = (ListenerInfo) listenerInfos[i];
if ((listenerInfo.listener instanceof IRegistryChangeListener) && scheduledDeltas.size() != 0) {
if (listenerInfo.filter == null || scheduledDeltas.containsKey(listenerInfo.filter)) {
SafeRunner.run(new ISafeRunnable() {
@Override
public void run() throws Exception {
((IRegistryChangeListener) listenerInfo.listener).registryChanged(new RegistryChangeEvent(scheduledDeltas, listenerInfo.filter));
}
@Override
public void handleException(Throwable exception) {
result.add(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, RegistryMessages.plugin_eventListenerError, exception));
}
});
}
}
if (listenerInfo.listener instanceof IRegistryEventListener) {
IRegistryEventListener extensionListener = (IRegistryEventListener) listenerInfo.listener;
IExtension[] extensions = extendedDelta.getExtensions(listenerInfo.filter);
IExtensionPoint[] extensionPoints = extendedDelta.getExtensionPoints(listenerInfo.filter);
if (extendedDelta.isAddition()) {
if (extensionPoints != null)
extensionListener.added(extensionPoints);
if (extensions != null)
extensionListener.added(extensions);
} else {
if (extensions != null)
extensionListener.removed(extensions);
if (extensionPoints != null)
extensionListener.removed(extensionPoints);
}
}
}
for (Iterator<?> iter = scheduledDeltas.values().iterator(); iter.hasNext();) {
((RegistryDelta) iter.next()).getObjectManager().close();
}
IObjectManager manager = extendedDelta.getObjectManager();
if (manager != null)
manager.close();
return result;
}
private RegistryEventThread eventThread = null;
protected final List<QueueElement> queue = new LinkedList<>();
public void scheduleChangeEvent(Object[] listenerInfos, Map<String, ?> scheduledDeltas) {
QueueElement newElement = new QueueElement(listenerInfos, scheduledDeltas);
if (eventThread == null) {
eventThread = new RegistryEventThread(this);
eventThread.start();
}
synchronized (queue) {
queue.add(newElement);
queue.notify();
}
}
private class QueueElement {
Object[] listenerInfos;
Map<String, ?> scheduledDeltas;
QueueElement(Object[] infos, Map<String, ?> deltas) {
this.scheduledDeltas = deltas;
listenerInfos = infos;
}
}
private class RegistryEventThread extends Thread {
private final ExtensionRegistry registry;
public RegistryEventThread(ExtensionRegistry registry) {
super("Extension Registry Event Dispatcher");
setDaemon(true);
this.registry = registry;
}
@Override
public void run() {
while (true) {
QueueElement element;
synchronized (queue) {
try {
while (queue.isEmpty())
queue.wait();
} catch (InterruptedException e) {
return;
}
element = queue.remove(0);
}
registry.processChangeEvent(element.listenerInfos, element.scheduledDeltas);
}
}
}
protected void stopChangeEventScheduler() {
if (eventThread != null) {
synchronized (queue) {
eventThread.interrupt();
eventThread = null;
}
}
}
private boolean checkReadWriteAccess(Object key, boolean persist) {
if (masterToken == key)
return true;
if (userToken == key && !persist)
return true;
return false;
}
public boolean addContribution(InputStream is, IContributor contributor, boolean persist, String contributionName, ResourceBundle translationBundle, Object key, long timestamp) {
boolean result = addContribution(is, contributor, persist, contributionName, translationBundle, key);
if (timestamp != 0)
aggregatedTimestamp.add(timestamp);
return result;
}
@Override
public boolean addContribution(InputStream is, IContributor contributor, boolean persist, String contributionName, ResourceBundle translationBundle, Object key) {
if (!checkReadWriteAccess(key, persist))
throw new IllegalArgumentException("Unauthorized access to the ExtensionRegistry.addContribution() method. Check if proper access token is supplied.");
if (contributionName == null)
contributionName = "";
RegistryContributor internalContributor = (RegistryContributor) contributor;
registryObjects.addContributor(internalContributor);
String ownerName = internalContributor.getActualName();
String message = NLS.bind(RegistryMessages.parse_problems, ownerName);
MultiStatus problems = new MultiStatus(RegistryMessages.OWNER_NAME, ExtensionsParser.PARSE_PROBLEM, message, null);
ExtensionsParser parser = new ExtensionsParser(problems, this);
Contribution contribution = getElementFactory().createContribution(internalContributor.getActualId(), persist);
try {
parser.parseManifest(strategy.getXMLParser(), new InputSource(is), contributionName, getObjectManager(), contribution, translationBundle);
int status = problems.getSeverity();
if (status != IStatus.OK) {
log(problems);
if (status == IStatus.ERROR || status == IStatus.CANCEL)
return false;
}
} catch (ParserConfigurationException | SAXException | IOException e) {
logError(ownerName, contributionName, e);
return false;
} finally {
try {
is.close();
} catch (IOException ioe) {
}
}
add(contribution);
return true;
}
private void logError(String owner, String contributionName, Exception e) {
String message = NLS.bind(RegistryMessages.parse_failedParsingManifest, owner + "/" + contributionName);
log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, 0, message, e));
}
public boolean addExtensionPoint(String identifier, IContributor contributor, boolean persist, String label, String schemaReference, Object token) throws IllegalArgumentException {
if (!checkReadWriteAccess(token, persist))
throw new IllegalArgumentException("Unauthorized access to the ExtensionRegistry.addExtensionPoint() method. Check if proper access token is supplied.");
RegistryContributor internalContributor = (RegistryContributor) contributor;
registryObjects.addContributor(internalContributor);
String contributorId = internalContributor.getActualId();
if (identifier == null) {
String message = NLS.bind(RegistryMessages.create_failedExtensionPoint, label);
log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, 0, message, null));
}
if (schemaReference == null)
schemaReference = "";
Contribution contribution = getElementFactory().createContribution(contributorId, persist);
ExtensionPoint currentExtPoint = getElementFactory().createExtensionPoint(persist);
String uniqueId;
String namespaceName;
int simpleIdStart = identifier.lastIndexOf('.');
if (simpleIdStart == -1) {
namespaceName = contribution.getDefaultNamespace();
uniqueId = namespaceName + '.' + identifier;
} else {
namespaceName = identifier.substring(0, simpleIdStart);
uniqueId = identifier;
}
currentExtPoint.setUniqueIdentifier(uniqueId);
currentExtPoint.setNamespace(namespaceName);
String labelNLS = translate(label, null);
currentExtPoint.setLabel(labelNLS);
currentExtPoint.setSchema(schemaReference);
if (!getObjectManager().addExtensionPoint(currentExtPoint, true)) {
if (debug()) {
String msg = NLS.bind(RegistryMessages.parse_duplicateExtensionPoint, uniqueId, contribution.getDefaultNamespace());
log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, 0, msg, null));
}
return false;
}
currentExtPoint.setContributorId(contributorId);
int[] contributionChildren = new int[3];
contributionChildren[Contribution.EXTENSION_POINT] = 1;
contributionChildren[Contribution.EXTENSION] = 0;
contributionChildren[Contribution.EXTENSION + 1] = currentExtPoint.getObjectId();
contribution.setRawChildren(contributionChildren);
add(contribution);
return true;
}
public boolean addExtension(String identifier, IContributor contributor, boolean persist, String label, String extensionPointId, ConfigurationElementDescription configurationElements, Object token) throws IllegalArgumentException {
if (!checkReadWriteAccess(token, persist))
throw new IllegalArgumentException("Unauthorized access to the ExtensionRegistry.addExtensionPoint() method. Check if proper access token is supplied.");
RegistryContributor internalContributor = (RegistryContributor) contributor;
registryObjects.addContributor(internalContributor);
String contributorId = internalContributor.getActualId();
Contribution contribution = getElementFactory().createContribution(contributorId, persist);
Extension currentExtension = getElementFactory().createExtension(persist);
String simpleId;
String namespaceName;
int simpleIdStart = identifier.lastIndexOf('.');
if (simpleIdStart != -1) {
simpleId = identifier.substring(simpleIdStart + 1);
namespaceName = identifier.substring(0, simpleIdStart);
} else {
simpleId = identifier;
namespaceName = contribution.getDefaultNamespace();
}
currentExtension.setSimpleIdentifier(simpleId);
currentExtension.setNamespaceIdentifier(namespaceName);
String extensionLabelNLS = translate(label, null);
currentExtension.setLabel(extensionLabelNLS);
String targetExtensionPointId;
if (extensionPointId.indexOf('.') == -1)
targetExtensionPointId = contribution.getDefaultNamespace() + '.' + extensionPointId;
else
targetExtensionPointId = extensionPointId;
currentExtension.setExtensionPointIdentifier(targetExtensionPointId);
if (simpleId != null && debug()) {
String uniqueId = namespaceName + '.' + simpleId;
IExtension existingExtension = getExtension(uniqueId);
if (existingExtension != null) {
String currentSupplier = contribution.getDefaultNamespace();
String existingSupplier = existingExtension.getContributor().getName();
String msg = NLS.bind(RegistryMessages.parse_duplicateExtension, new String[] {currentSupplier, existingSupplier, uniqueId});
log(new Status(IStatus.WARNING, RegistryMessages.OWNER_NAME, 0, msg, null));
return false;
}
}
getObjectManager().add(currentExtension, true);
createExtensionData(contributorId, configurationElements, currentExtension, persist);
currentExtension.setContributorId(contributorId);
int[] contributionChildren = new int[3];
contributionChildren[Contribution.EXTENSION_POINT] = 0;
contributionChildren[Contribution.EXTENSION] = 1;
contributionChildren[Contribution.EXTENSION + 1] = currentExtension.getObjectId();
contribution.setRawChildren(contributionChildren);
add(contribution);
return true;
}
private void createExtensionData(String contributorId, ConfigurationElementDescription description, RegistryObject parent, boolean persist) {
ConfigurationElement currentConfigurationElement = getElementFactory().createConfigurationElement(persist);
currentConfigurationElement.setContributorId(contributorId);
currentConfigurationElement.setName(description.getName());
ConfigurationElementAttribute[] descriptionProperties = description.getAttributes();
if (descriptionProperties != null && descriptionProperties.length != 0) {
int len = descriptionProperties.length;
String[] properties = new String[len * 2];
for (int i = 0; i < len; i++) {
properties[i * 2] = descriptionProperties[i].getName();
properties[i * 2 + 1] = translate(descriptionProperties[i].getValue(), null);
}
currentConfigurationElement.setProperties(properties);
} else
currentConfigurationElement.setProperties(RegistryObjectManager.EMPTY_STRING_ARRAY);
String value = description.getValue();
if (value != null)
currentConfigurationElement.setValue(value);
getObjectManager().add(currentConfigurationElement, true);
ConfigurationElementDescription[] children = description.getChildren();
if (children != null) {
for (int i = 0; i < children.length; i++) {
createExtensionData(contributorId, children[i], currentConfigurationElement, persist);
}
}
int[] oldValues = parent.getRawChildren();
int size = oldValues.length;
int[] newValues = new int[size + 1];
for (int i = 0; i < size; i++) {
newValues[i] = oldValues[i];
}
newValues[size] = currentConfigurationElement.getObjectId();
parent.setRawChildren(newValues);
currentConfigurationElement.setParentId(parent.getObjectId());
currentConfigurationElement.setParentType(parent instanceof ConfigurationElement ? RegistryObjectManager.CONFIGURATION_ELEMENT : RegistryObjectManager.EXTENSION);
}
@Override
public boolean removeExtension(IExtension extension, Object token) throws IllegalArgumentException {
if (!(extension instanceof ExtensionHandle))
return false;
return removeObject(((ExtensionHandle) extension).getObject(), false, token);
}
@Override
public boolean removeExtensionPoint(IExtensionPoint extensionPoint, Object token) throws IllegalArgumentException {
if (!(extensionPoint instanceof ExtensionPointHandle))
return false;
return removeObject(((ExtensionPointHandle) extensionPoint).getObject(), true, token);
}
private boolean removeObject(RegistryObject registryObject, boolean isExtensionPoint, Object token) {
if (!checkReadWriteAccess(token, registryObject.shouldPersist()))
throw new IllegalArgumentException("Unauthorized access to the ExtensionRegistry.removeExtension() method. Check if proper access token is supplied.");
int id = registryObject.getObjectId();
access.enterWrite();
try {
eventDelta = CombinedEventDelta.recordRemoval();
String namespace;
if (isExtensionPoint)
namespace = removeExtensionPoint(id);
else
namespace = removeExtension(id);
Map<Integer, RegistryObject> removed = new HashMap<>(1);
removed.put(Integer.valueOf(id), registryObject);
if (!isExtensionPoint)
registryObjects.addAssociatedObjects(removed, registryObject);
registryObjects.removeObjects(removed);
registryObjects.addNavigableObjects(removed);
IObjectManager manager = registryObjects.createDelegatingObjectManager(removed);
getDelta(namespace).setObjectManager(manager);
eventDelta.setObjectManager(manager);
registryObjects.unlinkChildFromContributions(id);
fireRegistryChangeEvent();
eventDelta = null;
} finally {
access.exitWrite();
}
return true;
}
@Override
public IContributor[] getAllContributors() {
access.enterRead();
try {
return registryObjects.getContributorsSync();
} finally {
access.exitRead();
}
}
public Object getTemporaryUserToken() {
return userToken;
}
@Override
public boolean isMultiLanguage() {
return isMultiLanguage;
}
public String[] translate(String[] nonTranslated, IContributor contributor, String locale) {
return strategy.translate(nonTranslated, contributor, locale);
}
public String getLocale() {
return strategy.getLocale();
}
public void logMultiLangError() {
if (mlErrorLogged)
return;
log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, 0, RegistryMessages.registry_non_multi_lang, new IllegalArgumentException()));
mlErrorLogged = true;
}
}