mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-208163 call getExtensionList not under our lock
This commit is contained in:
@@ -14,8 +14,9 @@ import java.util.List;
|
||||
*/
|
||||
public abstract class SmartExtensionPoint<Extension, V> {
|
||||
private final Collection<V> myExplicitExtensions;
|
||||
@SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized")
|
||||
private ExtensionPoint<Extension> myExtensionPoint;
|
||||
private List<V> myCache;
|
||||
private volatile List<V> myCache;
|
||||
|
||||
protected SmartExtensionPoint(@NotNull final Collection<V> explicitExtensions) {
|
||||
myExplicitExtensions = explicitExtensions;
|
||||
@@ -43,44 +44,61 @@ public abstract class SmartExtensionPoint<Extension, V> {
|
||||
|
||||
@NotNull
|
||||
public final List<V> getExtensions() {
|
||||
List<V> result = myCache;
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// it is ok to call getExtensionPoint several times - call is cheap is thread-safe
|
||||
ExtensionPoint<Extension> extensionPoint = myExtensionPoint;
|
||||
if (extensionPoint == null) {
|
||||
extensionPoint = getExtensionPoint();
|
||||
myExtensionPoint = extensionPoint;
|
||||
}
|
||||
|
||||
List<V> registeredExtensions = ContainerUtilRt.mapNotNull(extensionPoint.getExtensionList(), this::getExtension);
|
||||
synchronized (myExplicitExtensions) {
|
||||
List<V> result = myCache;
|
||||
if (result == null) {
|
||||
myExtensionPoint = getExtensionPoint();
|
||||
// EP will not add duplicated listener, so, it is safe to not care about is already added
|
||||
myExtensionPoint.addExtensionPointListener(new ExtensionPointAndAreaListener<Extension>() {
|
||||
@Override
|
||||
public void areaReplaced(@NotNull ExtensionsArea oldArea) {
|
||||
dropCache();
|
||||
result = myCache;
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// EP will not add duplicated listener, so, it is safe to not care about is already added
|
||||
extensionPoint.addExtensionPointListener(new ExtensionPointAndAreaListener<Extension>() {
|
||||
@Override
|
||||
public void areaReplaced(@NotNull ExtensionsArea oldArea) {
|
||||
dropCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void extensionRemoved(@NotNull final Extension extension, @Nullable final PluginDescriptor pluginDescriptor) {
|
||||
dropCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void extensionAdded(@NotNull final Extension extension, @Nullable final PluginDescriptor pluginDescriptor) {
|
||||
dropCache();
|
||||
}
|
||||
|
||||
private void dropCache() {
|
||||
if (myCache == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void extensionRemoved(@NotNull final Extension extension, @Nullable final PluginDescriptor pluginDescriptor) {
|
||||
dropCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void extensionAdded(@NotNull final Extension extension, @Nullable final PluginDescriptor pluginDescriptor) {
|
||||
dropCache();
|
||||
}
|
||||
|
||||
private void dropCache() {
|
||||
synchronized (myExplicitExtensions) {
|
||||
if (myCache != null) {
|
||||
myCache = null;
|
||||
myExtensionPoint.removeExtensionPointListener(this);
|
||||
myExtensionPoint = null;
|
||||
}
|
||||
synchronized (myExplicitExtensions) {
|
||||
if (myCache != null) {
|
||||
myCache = null;
|
||||
myExtensionPoint.removeExtensionPointListener(this);
|
||||
myExtensionPoint = null;
|
||||
}
|
||||
}
|
||||
}, false, null);
|
||||
}
|
||||
}, false, null);
|
||||
|
||||
List<V> registeredExtensions = ContainerUtilRt.mapNotNull(myExtensionPoint.getExtensionList(), this::getExtension);
|
||||
result = new ArrayList<>(myExplicitExtensions.size() + registeredExtensions.size());
|
||||
result.addAll(myExplicitExtensions);
|
||||
result.addAll(registeredExtensions);
|
||||
myCache = result;
|
||||
}
|
||||
result = new ArrayList<>(myExplicitExtensions.size() + registeredExtensions.size());
|
||||
result.addAll(myExplicitExtensions);
|
||||
result.addAll(registeredExtensions);
|
||||
myCache = result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user