processor) {
for (Library library : table.getLibraries()) {
- clearKind(kind, library);
+ processor.accept(library);
}
}
- private static void clearKind(@NotNull PersistentLibraryKind> kind, @NotNull Library library) {
+ private static void forgetKind(@NotNull PersistentLibraryKind> kind, @NotNull Library library) {
if (kind.equals(((LibraryEx)library).getKind())) {
LibraryEx.ModifiableModelEx model = (LibraryEx.ModifiableModelEx)library.getModifiableModel();
- model.clearKind();
+ model.forgetKind();
+ model.commit();
+ }
+ }
+
+ private static void rememberKind(@NotNull PersistentLibraryKind> kind, @NotNull Library library) {
+ PersistentLibraryKind> libraryKind = ((LibraryEx)library).getKind();
+ if (libraryKind instanceof UnknownLibraryKind && libraryKind.getKindId().equals(kind.getKindId())) {
+ LibraryEx.ModifiableModelEx model = (LibraryEx.ModifiableModelEx)library.getModifiableModel();
+ model.restoreKind();
model.commit();
}
}
diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/libraries/LibraryType.java b/platform/lang-impl/src/com/intellij/openapi/roots/libraries/LibraryType.java
index 9688fdb89447..22ac8f1676b9 100644
--- a/platform/lang-impl/src/com/intellij/openapi/roots/libraries/LibraryType.java
+++ b/platform/lang-impl/src/com/intellij/openapi/roots/libraries/LibraryType.java
@@ -19,6 +19,7 @@ import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.OrderRootType;
+import com.intellij.openapi.roots.impl.libraries.UnknownLibraryKind;
import com.intellij.openapi.roots.libraries.ui.LibraryEditorComponent;
import com.intellij.openapi.roots.libraries.ui.LibraryPropertiesEditor;
import com.intellij.openapi.roots.libraries.ui.LibraryRootsComponentDescriptor;
@@ -108,6 +109,9 @@ public abstract class LibraryType extends LibraryPr
return type;
}
}
+ if (kind instanceof UnknownLibraryKind) {
+ return new UnknownLibraryType((UnknownLibraryKind)kind);
+ }
throw new IllegalArgumentException("Library with kind " + kind + " is not registered");
}
}
diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/libraries/UnknownLibraryType.java b/platform/lang-impl/src/com/intellij/openapi/roots/libraries/UnknownLibraryType.java
new file mode 100644
index 000000000000..d3c9a94a65a0
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/openapi/roots/libraries/UnknownLibraryType.java
@@ -0,0 +1,41 @@
+// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.openapi.roots.libraries;
+
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.impl.libraries.UnknownLibraryKind;
+import com.intellij.openapi.roots.libraries.ui.LibraryEditorComponent;
+import com.intellij.openapi.roots.libraries.ui.LibraryPropertiesEditor;
+import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+public class UnknownLibraryType extends LibraryType {
+ public UnknownLibraryType(@NotNull UnknownLibraryKind kind) {
+ super(kind);
+ }
+
+ @Override
+ public @Nullable String getCreateActionName() {
+ return null;
+ }
+
+ @Override
+ public @Nullable NewLibraryConfiguration createNewLibrary(@NotNull JComponent parentComponent,
+ @Nullable VirtualFile contextDirectory,
+ @NotNull Project project) {
+ return null;
+ }
+
+ @Override
+ public @Nullable LibraryPropertiesEditor createPropertiesEditor(@NotNull LibraryEditorComponent editorComponent) {
+ return null;
+ }
+
+ @Override
+ public @Nullable Icon getIcon(UnknownLibraryKind.@Nullable UnknownLibraryProperties properties) {
+ return AllIcons.Nodes.Unknown;
+ }
+}
diff --git a/platform/projectModel-api/src/com/intellij/openapi/roots/impl/libraries/LibraryEx.java b/platform/projectModel-api/src/com/intellij/openapi/roots/impl/libraries/LibraryEx.java
index 0c1afe5bddeb..268140229359 100644
--- a/platform/projectModel-api/src/com/intellij/openapi/roots/impl/libraries/LibraryEx.java
+++ b/platform/projectModel-api/src/com/intellij/openapi/roots/impl/libraries/LibraryEx.java
@@ -82,7 +82,9 @@ public interface LibraryEx extends Library {
/**
* Removes custom library kind and associated properties if any
*/
- void clearKind();
+ void forgetKind();
+
+ void restoreKind();
/**
* Add a URL to list of directories excluded from the library. The directory specified by {@code url} must be located under some
diff --git a/platform/projectModel-api/src/com/intellij/openapi/roots/libraries/LibraryKind.java b/platform/projectModel-api/src/com/intellij/openapi/roots/libraries/LibraryKind.java
index 8c2cac08d359..91fb93b46cf8 100644
--- a/platform/projectModel-api/src/com/intellij/openapi/roots/libraries/LibraryKind.java
+++ b/platform/projectModel-api/src/com/intellij/openapi/roots/libraries/LibraryKind.java
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.roots.libraries;
+import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -30,7 +31,8 @@ public class LibraryKind {
*/
public LibraryKind(@NotNull @NonNls String kindId) {
myKindId = kindId;
- if (ourAllKinds.containsKey(kindId)) {
+ LibraryKind kind = ourAllKinds.get(kindId);
+ if (kind != null && !(kind instanceof TemporaryLibraryKind)) {
throw new IllegalArgumentException("Kind " + kindId + " is not unique");
}
ourAllKinds.put(kindId, this);
@@ -56,4 +58,14 @@ public class LibraryKind {
public static LibraryKind findById(String kindId) {
return ourAllKinds.get(kindId);
}
+
+ @ApiStatus.Internal
+ public static void unregisterKind(@NotNull LibraryKind kind) {
+ ourAllKinds.remove(kind.getKindId());
+ }
+
+ @ApiStatus.Internal
+ public static void registerKind(@NotNull LibraryKind kind) {
+ ourAllKinds.put(kind.getKindId(), kind);
+ }
}
diff --git a/platform/projectModel-api/src/com/intellij/openapi/roots/libraries/TemporaryLibraryKind.java b/platform/projectModel-api/src/com/intellij/openapi/roots/libraries/TemporaryLibraryKind.java
new file mode 100644
index 000000000000..b374ee399ac0
--- /dev/null
+++ b/platform/projectModel-api/src/com/intellij/openapi/roots/libraries/TemporaryLibraryKind.java
@@ -0,0 +1,11 @@
+// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.openapi.roots.libraries;
+
+import org.jetbrains.annotations.ApiStatus;
+
+/**
+ * Marker interface for implementations of {@link LibraryKind} which are used to replace the real implementations. For internal use only.
+ */
+@ApiStatus.Internal
+public interface TemporaryLibraryKind {
+}
diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryImpl.java
index 7b8712b11f32..db4c2a050ec7 100644
--- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryImpl.java
+++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryImpl.java
@@ -117,8 +117,12 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
@Nullable
private static PersistentLibraryKind> findPersistentLibraryKind(@NotNull Element element) {
String typeString = element.getAttributeValue(LIBRARY_TYPE_ATTR);
+ if (typeString == null) return null;
LibraryKind kind = LibraryKind.findById(typeString);
- if (kind != null && !(kind instanceof PersistentLibraryKind>)) {
+ if (kind == null) {
+ return UnknownLibraryKind.getOrCreate(typeString);
+ }
+ if (!(kind instanceof PersistentLibraryKind>)) {
LOG.error("Cannot load non-persistable library kind: " + typeString);
return null;
}
@@ -293,10 +297,16 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
if (typeId == null) return;
myKind = (PersistentLibraryKind>) LibraryKind.findById(typeId);
- if (myKind == null) return;
+ final Element propertiesElement = element.getChild(JpsLibraryTableSerializer.PROPERTIES_TAG);
+ if (myKind == null) {
+ myKind = UnknownLibraryKind.getOrCreate(typeId);
+ UnknownLibraryKind.UnknownLibraryProperties properties = new UnknownLibraryKind.UnknownLibraryProperties();
+ properties.setConfiguration(propertiesElement);
+ myProperties = properties;
+ return;
+ }
myProperties = myKind.createDefaultProperties();
- final Element propertiesElement = element.getChild(JpsLibraryTableSerializer.PROPERTIES_TAG);
if (propertiesElement != null) {
ComponentSerializationUtil.loadComponentState(myProperties, propertiesElement);
}
@@ -354,7 +364,7 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
LOG.assertTrue(myProperties != null, "Properties is 'null' in library with kind " + myKind);
final Object state = myProperties.getState();
if (state != null) {
- final Element propertiesElement = XmlSerializer.serialize(state);
+ final Element propertiesElement = state instanceof Element ? ((Element)state).clone() : XmlSerializer.serialize(state);
if (propertiesElement != null) {
element.addContent(propertiesElement.setName(JpsLibraryTableSerializer.PROPERTIES_TAG));
}
@@ -438,9 +448,30 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
}
@Override
- public void clearKind() {
- myKind = null;
- myProperties = null;
+ public void forgetKind() {
+ if (myKind == null) return;
+
+ myKind = UnknownLibraryKind.getOrCreate(myKind.getKindId());
+ Object propertiesState = myProperties.getState();
+ if (propertiesState != null) {
+ UnknownLibraryKind.UnknownLibraryProperties properties = new UnknownLibraryKind.UnknownLibraryProperties();
+ properties.setConfiguration(XmlSerializer.serialize(propertiesState));
+ myProperties = properties;
+ }
+ else {
+ myProperties = null;
+ }
+ }
+
+ @Override
+ public void restoreKind() {
+ if (myKind == null || !(myKind instanceof UnknownLibraryKind)) return;
+ myKind = (PersistentLibraryKind>)LibraryKind.findById(myKind.getKindId());
+ Element configuration = ((UnknownLibraryKind.UnknownLibraryProperties)myProperties).getConfiguration();
+ myProperties = myKind.createDefaultProperties();
+ if (configuration != null) {
+ ComponentSerializationUtil.loadComponentState(myProperties, configuration);
+ }
}
@Override
diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/UnknownLibraryKind.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/UnknownLibraryKind.java
new file mode 100644
index 000000000000..225804ad63ad
--- /dev/null
+++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/UnknownLibraryKind.java
@@ -0,0 +1,89 @@
+// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.openapi.roots.impl.libraries;
+
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.roots.libraries.LibraryKind;
+import com.intellij.openapi.roots.libraries.LibraryProperties;
+import com.intellij.openapi.roots.libraries.PersistentLibraryKind;
+import com.intellij.openapi.roots.libraries.TemporaryLibraryKind;
+import com.intellij.openapi.util.JDOMUtil;
+import org.jdom.Element;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class UnknownLibraryKind extends PersistentLibraryKind implements TemporaryLibraryKind {
+ private static final Logger LOG = Logger.getInstance(UnknownLibraryKind.class);
+
+ private UnknownLibraryKind(@NotNull String kindId) {
+ super(kindId);
+ }
+
+ @Override
+ public int hashCode() {
+ return getKindId().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof UnknownLibraryKind && ((UnknownLibraryKind)obj).getKindId().equals(getKindId());
+ }
+
+ @NotNull
+ @Override
+ public UnknownLibraryProperties createDefaultProperties() {
+ return new UnknownLibraryProperties();
+ }
+
+ public static UnknownLibraryKind getOrCreate(@NotNull String kindId) {
+ LibraryKind kind = LibraryKind.findById(kindId);
+ if (kind instanceof UnknownLibraryKind) {
+ return (UnknownLibraryKind)kind;
+ }
+ if (kind != null) {
+ LOG.error("Trying to create UnknownLibraryKind for known kind " + kind);
+ }
+ return new UnknownLibraryKind(kindId);
+ }
+
+ @Override
+ public String toString() {
+ return "UnknownLibraryKind:" + getKindId();
+ }
+
+ public static class UnknownLibraryProperties extends LibraryProperties {
+ private Element myConfiguration;
+
+ public Element getConfiguration() {
+ return myConfiguration;
+ }
+
+ public void setConfiguration(Element configuration) {
+ myConfiguration = configuration;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof UnknownLibraryProperties)) return false;
+ Element configuration = ((UnknownLibraryProperties)obj).myConfiguration;
+ if (configuration == null && myConfiguration == null) return true;
+ if (configuration == null || myConfiguration == null) return false;
+ return JDOMUtil.areElementsEqual(myConfiguration, configuration);
+ }
+
+ @Override
+ public int hashCode() {
+ return JDOMUtil.hashCode(myConfiguration, false);
+ }
+
+ @Nullable
+ @Override
+ public Element getState() {
+ return myConfiguration;
+ }
+
+ @Override
+ public void loadState(@NotNull Element state) {
+ myConfiguration = state;
+ }
+ }
+}
diff --git a/platform/workspaceModel-ide/src/com/intellij/workspace/legacyBridge/libraries/libraries/LegacyBridgeLibraryImpl.kt b/platform/workspaceModel-ide/src/com/intellij/workspace/legacyBridge/libraries/libraries/LegacyBridgeLibraryImpl.kt
index ebbf8552f546..ca0b73a97f7f 100644
--- a/platform/workspaceModel-ide/src/com/intellij/workspace/legacyBridge/libraries/libraries/LegacyBridgeLibraryImpl.kt
+++ b/platform/workspaceModel-ide/src/com/intellij/workspace/legacyBridge/libraries/libraries/LegacyBridgeLibraryImpl.kt
@@ -117,7 +117,7 @@ internal class LegacyBridgeLibraryImpl(
private val libraryEntity
get() = entityStore.cachedValue(libraryEntityValue, entityId)
- private val snapshotValue = CachedValueWithParameter { storage, id: LibraryId ->
+ internal val snapshotValue = CachedValueWithParameter { storage, id: LibraryId ->
LibraryViaTypedEntity(
libraryImpl = this,
libraryEntity = storage.resolve(id) ?: object : LibraryEntity {
diff --git a/platform/workspaceModel-ide/src/com/intellij/workspace/legacyBridge/libraries/libraries/LegacyBridgeLibraryModifiableModelImpl.kt b/platform/workspaceModel-ide/src/com/intellij/workspace/legacyBridge/libraries/libraries/LegacyBridgeLibraryModifiableModelImpl.kt
index 82c46c06c4e3..1a6f502b217d 100644
--- a/platform/workspaceModel-ide/src/com/intellij/workspace/legacyBridge/libraries/libraries/LegacyBridgeLibraryModifiableModelImpl.kt
+++ b/platform/workspaceModel-ide/src/com/intellij/workspace/legacyBridge/libraries/libraries/LegacyBridgeLibraryModifiableModelImpl.kt
@@ -28,6 +28,7 @@ internal class LegacyBridgeLibraryModifiableModelImpl(
) : LegacyBridgeModifiableBase(diff), LibraryEx.ModifiableModelEx, LibraryEx, RootProvider {
private var entityId = originalLibrarySnapshot.libraryEntity.persistentId()
+ private var reloadKind = false
private val currentLibraryValue = CachedValue { storage ->
val newLibrary = LibraryViaTypedEntity(
@@ -79,9 +80,13 @@ internal class LegacyBridgeLibraryModifiableModelImpl(
assertModelIsLive()
modelIsCommittedOrDisposed = true
- if (!isChanged) return
- committer(this, diff)
+ if (reloadKind) {
+ originalLibrary.entityStore.clearCachedValue(originalLibrary.snapshotValue, originalLibrary.entityId)
+ }
+ if (isChanged) {
+ committer(this, diff)
+ }
}
private fun update(updater: ModifiableLibraryEntity.() -> Unit) {
@@ -274,14 +279,12 @@ internal class LegacyBridgeLibraryModifiableModelImpl(
}
}
- override fun clearKind() {
- assertModelIsLive()
- if (kind == null) return
+ override fun forgetKind() {
+ reloadKind = true
+ }
- val properties = currentLibrary.libraryEntity.referrers(LibraryPropertiesEntity::library).toList()
- for (propertiesEntity in properties) {
- diff.removeEntity(propertiesEntity)
- }
+ override fun restoreKind() {
+ reloadKind = true
}
private fun isUnderRoots(url: VirtualFileUrl, roots: Collection): Boolean {
diff --git a/platform/workspaceModel-ide/src/com/intellij/workspace/legacyBridge/typedModel/library/LibraryViaTypedEntity.kt b/platform/workspaceModel-ide/src/com/intellij/workspace/legacyBridge/typedModel/library/LibraryViaTypedEntity.kt
index 7ca2f188d9c3..386bac2928c6 100644
--- a/platform/workspaceModel-ide/src/com/intellij/workspace/legacyBridge/typedModel/library/LibraryViaTypedEntity.kt
+++ b/platform/workspaceModel-ide/src/com/intellij/workspace/legacyBridge/typedModel/library/LibraryViaTypedEntity.kt
@@ -7,6 +7,7 @@ import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.ProjectModelExternalSource
import com.intellij.openapi.roots.RootProvider
import com.intellij.openapi.roots.impl.libraries.LibraryEx
+import com.intellij.openapi.roots.impl.libraries.UnknownLibraryKind
import com.intellij.openapi.roots.libraries.*
import com.intellij.openapi.util.JDOMUtil
import com.intellij.openapi.vfs.VirtualFile
@@ -36,7 +37,7 @@ internal class LibraryViaTypedEntity(val libraryImpl: LegacyBridgeLibraryImpl,
LegacyBridgeFileContainer(urls, jarDirs)
}
private val excludedRoots = if (libraryEntity.excludedRoots.isNotEmpty()) LegacyBridgeFileContainer(libraryEntity.excludedRoots, emptyList()) else null
- private val libraryKind = libraryEntity.getCustomProperties()?.libraryType?.let { LibraryKind.findById(it) } as? PersistentLibraryKind<*>
+ private val libraryKind = libraryEntity.getCustomProperties()?.libraryType?.let { LibraryKind.findById(it) ?: UnknownLibraryKind.getOrCreate(it) } as? PersistentLibraryKind<*>
private val properties = loadProperties()
private fun loadProperties(): LibraryProperties<*>? {