[workspace model] provide implementation of FacetManager which stores data in workspa...
[idea/community.git] / platform / workspaceModel-ide / src / com / intellij / workspace / legacyBridge / facet / FacetManagerViaWorkspaceModel.kt
1 // Copyright 2000-2019 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.
2 package com.intellij.workspace.legacyBridge.facet
3
4 import com.google.common.collect.HashBiMap
5 import com.intellij.facet.*
6 import com.intellij.facet.impl.FacetModelBase
7 import com.intellij.facet.impl.FacetUtil
8 import com.intellij.openapi.application.runWriteAction
9 import com.intellij.openapi.module.Module
10 import com.intellij.openapi.project.ProjectBundle
11 import com.intellij.openapi.util.JDOMUtil
12 import com.intellij.workspace.api.*
13 import com.intellij.workspace.ide.WorkspaceModel
14 import com.intellij.workspace.legacyBridge.intellij.LegacyBridgeModule
15 import org.jetbrains.jps.model.serialization.facet.FacetState
16
17 class FacetManagerViaWorkspaceModel(module: Module) : FacetManagerBase() {
18   internal val module = module as LegacyBridgeModule
19   internal val model = FacetModelViaWorkspaceModel(this.module)
20
21   private fun isThisModule(moduleEntity: ModuleEntity) = moduleEntity.name == module.name
22
23   override fun checkConsistency() {
24     model.checkConsistency(module.entityStore.current.entities(FacetEntity::class.java).filter { isThisModule(it.module) }.toList())
25   }
26
27   override fun facetConfigurationChanged(facet: Facet<*>) {
28     val facetEntity = model.getEntity(facet)
29     if (facetEntity != null) {
30       val facetConfigurationXml = FacetUtil.saveFacetConfiguration(facet)?.let { JDOMUtil.write(it) }
31       if (facetConfigurationXml != facetEntity.configurationXmlTag) {
32         runWriteAction {
33           WorkspaceModel.getInstance(module.project).updateProjectModel {
34             it.modifyEntity(ModifiableFacetEntity::class.java, facetEntity) {
35               this.configurationXmlTag = facetConfigurationXml
36             }
37           }
38         }
39       }
40     }
41     super.facetConfigurationChanged(facet)
42   }
43
44   override fun getModel(): FacetModel = model
45   override fun getModule(): Module = module
46   override fun createModifiableModel(): ModifiableFacetModel {
47     val diff = TypedEntityStorageDiffBuilder.create(module.entityStore.current)
48     return ModifiableFacetModelViaWorkspaceModel(module.entityStore.current, diff, module, this)
49   }
50
51 }
52
53 internal open class FacetModelViaWorkspaceModel(protected val legacyBridgeModule: LegacyBridgeModule) : FacetModelBase() {
54   protected val entityToFacet: HashBiMap<FacetEntity, Facet<*>> = HashBiMap.create<FacetEntity, Facet<*>>()
55
56   override fun getAllFacets(): Array<Facet<*>> {
57     return entityToFacet.values.toTypedArray()
58   }
59
60   internal fun getOrCreateFacet(entity: FacetEntity): Facet<*> {
61     return entityToFacet.getOrPut(entity) { createFacet(entity) }
62   }
63
64   internal fun getFacet(entity: FacetEntity): Facet<*>? = entityToFacet[entity]
65
66   internal fun getEntity(facet: Facet<*>): FacetEntity? = entityToFacet.inverse()[facet]
67
68   private fun createFacet(entity: FacetEntity): Facet<*> {
69     val registry = FacetTypeRegistry.getInstance()
70     val facetType = registry.findFacetType(entity.facetType)
71     val underlyingFacet = entity.underlyingFacet?.let { getOrCreateFacet(it) }
72     if (facetType == null) {
73       return FacetManagerBase.createInvalidFacet(legacyBridgeModule, FacetState().apply {
74         name = entity.name
75         setFacetType(entity.facetType)
76         configuration = entity.configurationXmlTag?.let { JDOMUtil.load(it) }
77       }, underlyingFacet, ProjectBundle.message("error.message.unknown.facet.type.0", entity.facetType), true)
78     }
79
80     val configuration = facetType.createDefaultConfiguration()
81     val configurationXmlTag = entity.configurationXmlTag
82     if (configurationXmlTag != null) {
83       FacetUtil.loadFacetConfiguration(configuration, JDOMUtil.load(configurationXmlTag))
84     }
85     return facetType.createFacet(legacyBridgeModule, entity.name, configuration, underlyingFacet)
86   }
87
88   fun populateFrom(mapping: HashBiMap<FacetEntity, Facet<*>>) {
89     entityToFacet.putAll(mapping)
90   }
91
92   internal fun populateFrom(mapping: FacetModelViaWorkspaceModel) {
93     entityToFacet.putAll(mapping.entityToFacet)
94   }
95
96   fun removeEntity(entity: FacetEntity): Facet<*>? {
97     return entityToFacet.remove(entity)
98   }
99
100   fun updateEntity(oldEntity: FacetEntity, newEntity: FacetEntity): Facet<*>? {
101     val oldFacet = entityToFacet.remove(oldEntity)
102     if (oldFacet != null) {
103       entityToFacet[newEntity] = oldFacet
104     }
105     return entityToFacet[newEntity]
106   }
107
108   public override fun facetsChanged() {
109     super.facetsChanged()
110   }
111
112   fun checkConsistency(facetEntities: List<FacetEntity>) {
113     val facetEntitiesSet = facetEntities.toSet()
114     for (entity in facetEntities) {
115       val facet = entityToFacet[entity]
116       if (facet == null) {
117         throw IllegalStateException("No facet registered for $entity (name = ${entity.name})")
118       }
119       if (facet.name != entity.name) {
120         throw IllegalStateException("Different name")
121       }
122       val entityFromMapping = entityToFacet.inverse()[facet]!!
123       val facetsFromStorage = entityFromMapping.module.facets.toSet()
124       if (facetsFromStorage != facetEntitiesSet) {
125         throw IllegalStateException("Different set of facets from $entity storage: expected $facetEntitiesSet but was $facetsFromStorage")
126       }
127     }
128     val staleEntity = (entityToFacet.keys - facetEntities).firstOrNull()
129     if (staleEntity != null) {
130       throw IllegalStateException("Stale entity $staleEntity (name = ${staleEntity.name}) in the mapping")
131     }
132   }
133 }