diff --git a/platform/configuration-store-impl/src/ApplicationStoreImpl.kt b/platform/configuration-store-impl/src/ApplicationStoreImpl.kt index 8f3e8cf6735f..2e77961f19a4 100644 --- a/platform/configuration-store-impl/src/ApplicationStoreImpl.kt +++ b/platform/configuration-store-impl/src/ApplicationStoreImpl.kt @@ -25,7 +25,7 @@ const val APP_CONFIG = "\$APP_CONFIG$" private const val FILE_STORAGE_DIR = "options" private const val DEFAULT_STORAGE_SPEC = "${PathManager.DEFAULT_OPTIONS_FILE_NAME}${FileStorageCoreUtil.DEFAULT_EXT}" -class ApplicationStoreImpl(private val application: Application, pathMacroManager: PathMacroManager? = null) : ComponentStoreImpl() { +class ApplicationStoreImpl(private val application: Application, pathMacroManager: PathMacroManager? = null) : ComponentStoreWithExtraComponents() { override val storageManager = ApplicationStorageManager(application, pathMacroManager) // number of app components require some state, so, we load default state in test mode diff --git a/platform/configuration-store-impl/src/ComponentStoreImpl.kt b/platform/configuration-store-impl/src/ComponentStoreImpl.kt index f76a1101ad3e..b0733b6d41f2 100644 --- a/platform/configuration-store-impl/src/ComponentStoreImpl.kt +++ b/platform/configuration-store-impl/src/ComponentStoreImpl.kt @@ -23,7 +23,6 @@ import com.intellij.openapi.util.JDOMExternalizable import com.intellij.openapi.util.JDOMUtil import com.intellij.openapi.util.registry.Registry import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess -import com.intellij.project.isDirectoryBased import com.intellij.ui.AppUIUtil import com.intellij.util.ArrayUtilRt import com.intellij.util.SmartList @@ -74,7 +73,6 @@ internal fun setRoamableComponentSaveThreshold(thresholdInSeconds: Int) { abstract class ComponentStoreImpl : IComponentStore { private val components = Collections.synchronizedMap(THashMap()) - private val settingsSavingComponents = com.intellij.util.containers.ContainerUtil.createLockFreeCopyOnWriteList() internal open val project: Project? get() = null @@ -84,11 +82,7 @@ abstract class ComponentStoreImpl : IComponentStore { override abstract val storageManager: StateStorageManager - override final fun initComponent(component: Any, isService: Boolean) { - if (component is SettingsSavingComponent) { - settingsSavingComponents.add(component) - } - + override fun initComponent(component: Any, isService: Boolean) { var componentName = "" try { @Suppress("DEPRECATION") @@ -130,50 +124,27 @@ abstract class ComponentStoreImpl : IComponentStore { return componentName } - override fun save(readonlyFiles: MutableList, isForce: Boolean) { - var errors: MutableList? = null + override final fun save(readonlyFiles: MutableList, isForce: Boolean) { + val errors: MutableList = SmartList() - fun execute(handler: () -> Unit) { - try { - handler() - } - catch (e: Throwable) { - if (errors == null) { - errors = SmartList() - } - errors!!.add(e) - } - } - - // component state uses scheme manager in an ipr project, so, we must save it before - val isIprProject = project?.let { !it.isDirectoryBased } ?: false - if (isIprProject) { - settingsSavingComponents.firstOrNull { it is SchemeManagerFactoryBase }?.let { - execute { - it.save() - } - } - } + beforeSaveComponents(errors) val externalizationSession = if (components.isEmpty()) null else storageManager.startExternalization() if (externalizationSession != null) { - errors = doSaveComponents(isForce, externalizationSession, errors) + doSaveComponents(isForce, externalizationSession, errors) } - for (settingsSavingComponent in settingsSavingComponents) { - if (!isIprProject || settingsSavingComponent !is SchemeManagerFactoryBase) { - execute { - settingsSavingComponent.save() - } - } - } + afterSaveComponents(errors) - execute { + try { saveAdditionalComponents(isForce) } + catch (e: Throwable) { + errors.add(e) + } if (externalizationSession != null) { - errors = doSave(externalizationSession.createSaveSessions(), readonlyFiles, errors) + doSave(externalizationSession.createSaveSessions(), readonlyFiles, errors) } CompoundRuntimeException.throwIfNotEmpty(errors) } @@ -181,10 +152,15 @@ abstract class ComponentStoreImpl : IComponentStore { protected open fun saveAdditionalComponents(isForce: Boolean) { } - private fun doSaveComponents(isForce: Boolean, externalizationSession: ExternalizationSession, _errors: MutableList?): MutableList? { + protected open fun beforeSaveComponents(errors: MutableList) { + } + + protected open fun afterSaveComponents(errors: MutableList) { + } + + protected open fun doSaveComponents(isForce: Boolean, externalizationSession: ExternalizationSession, errors: MutableList): MutableList? { val isUseModificationCount = Registry.`is`("store.save.use.modificationCount", true) - var errors = _errors val names = ArrayUtilRt.toStringArray(components.keys) Arrays.sort(names) val timeLogPrefix = "Saving" @@ -223,9 +199,6 @@ abstract class ComponentStoreImpl : IComponentStore { info.updateModificationCount(currentModificationCount) } catch (e: Throwable) { - if (errors == null) { - errors = SmartList() - } errors.add(Exception("Cannot get $name component state", e)) } @@ -259,7 +232,9 @@ abstract class ComponentStoreImpl : IComponentStore { runUndoTransparentWriteAction { try { VfsRootAccess.allowRootAccess(absolutePath) - CompoundRuntimeException.throwIfNotEmpty(doSave(sessions)) + val errors: MutableList = SmartList() + doSave(sessions, errors = errors) + CompoundRuntimeException.throwIfNotEmpty(errors) } finally { VfsRootAccess.disallowRootAccess(absolutePath) @@ -283,12 +258,11 @@ abstract class ComponentStoreImpl : IComponentStore { protected open fun doSave(saveSessions: List, readonlyFiles: MutableList = arrayListOf(), - prevErrors: MutableList? = null): MutableList? { - var errors = prevErrors + errors: MutableList) { for (session in saveSessions) { - errors = executeSave(session, readonlyFiles, prevErrors) + executeSave(session, readonlyFiles, errors) } - return errors + return } private fun initJdomExternalizable(@Suppress("DEPRECATION") component: JDOMExternalizable, componentName: String): String? { @@ -541,10 +515,7 @@ abstract class ComponentStoreImpl : IComponentStore { } } -internal fun executeSave(session: SaveSession, - readonlyFiles: MutableList, - previousErrors: MutableList?): MutableList? { - var errors = previousErrors +internal fun executeSave(session: SaveSession, readonlyFiles: MutableList, errors: MutableList) { try { session.save() } @@ -553,13 +524,8 @@ internal fun executeSave(session: SaveSession, readonlyFiles.add(SaveSessionAndFile(e.session ?: session, e.file)) } catch (e: Exception) { - if (errors == null) { - errors = SmartList() - } errors.add(e) } - - return errors } private fun findNonDeprecated(storages: Array) = storages.firstOrNull { !it.deprecated } ?: throw AssertionError( diff --git a/platform/configuration-store-impl/src/ComponentStoreWithExtraComponents.kt b/platform/configuration-store-impl/src/ComponentStoreWithExtraComponents.kt new file mode 100644 index 000000000000..e29dc6b081b3 --- /dev/null +++ b/platform/configuration-store-impl/src/ComponentStoreWithExtraComponents.kt @@ -0,0 +1,46 @@ +// Copyright 2000-2018 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.configurationStore + +import com.intellij.openapi.components.SettingsSavingComponent +import com.intellij.project.isDirectoryBased + +abstract class ComponentStoreWithExtraComponents : ComponentStoreImpl() { + private val settingsSavingComponents = com.intellij.util.containers.ContainerUtil.createLockFreeCopyOnWriteList() + + override fun initComponent(component: Any, isService: Boolean) { + if (component is SettingsSavingComponent) { + settingsSavingComponents.add(component) + } + + super.initComponent(component, isService) + } + + override final fun beforeSaveComponents(errors: MutableList) { + // component state uses scheme manager in an ipr project, so, we must save it before + val isIprProject = project?.let { !it.isDirectoryBased } ?: false + if (isIprProject) { + settingsSavingComponents.firstOrNull { it is SchemeManagerFactoryBase }?.let { + try { + it.save() + } + catch(e: Throwable) { + errors.add(e) + } + } + } + } + + override final fun afterSaveComponents(errors: MutableList) { + val isIprProject = project?.let { !it.isDirectoryBased } ?: false + for (settingsSavingComponent in settingsSavingComponents) { + if (!isIprProject || settingsSavingComponent !is SchemeManagerFactoryBase) { + try { + settingsSavingComponent.save() + } + catch (e: Throwable) { + errors.add(e) + } + } + } + } +} diff --git a/platform/configuration-store-impl/src/ProjectStoreImpl.kt b/platform/configuration-store-impl/src/ProjectStoreImpl.kt index ec26d3d02e09..9b3150c7d44c 100644 --- a/platform/configuration-store-impl/src/ProjectStoreImpl.kt +++ b/platform/configuration-store-impl/src/ProjectStoreImpl.kt @@ -49,7 +49,7 @@ internal val PROJECT_FILE_STORAGE_ANNOTATION = FileStorageAnnotation(PROJECT_FIL internal val DEPRECATED_PROJECT_FILE_STORAGE_ANNOTATION = FileStorageAnnotation(PROJECT_FILE, true) // cannot be `internal`, used in Upsource -abstract class ProjectStoreBase(override final val project: ProjectImpl) : ComponentStoreImpl(), IProjectStore { +abstract class ProjectStoreBase(override final val project: ProjectImpl) : ComponentStoreWithExtraComponents(), IProjectStore { // protected setter used in upsource // Zelix KlassMaster - ERROR: Could not find method 'getScheme()' var scheme = StorageScheme.DEFAULT @@ -302,7 +302,7 @@ private open class ProjectStoreImpl(project: ProjectImpl, private val pathMacroM } } - override fun doSave(saveSessions: List, readonlyFiles: MutableList, prevErrors: MutableList?): MutableList? { + override fun doSave(saveSessions: List, readonlyFiles: MutableList, errors: MutableList) { try { saveProjectName() } @@ -310,17 +310,16 @@ private open class ProjectStoreImpl(project: ProjectImpl, private val pathMacroM LOG.error("Unable to store project name", e) } - var errors = prevErrors beforeSave(readonlyFiles) - errors = super.doSave(saveSessions, readonlyFiles, errors) + super.doSave(saveSessions, readonlyFiles, errors) val notifications = NotificationsManager.getNotificationsManager().getNotificationsOfType(UnableToSaveProjectNotification::class.java, project) if (readonlyFiles.isEmpty()) { for (notification in notifications) { notification.expire() } - return errors + return } if (!notifications.isEmpty()) { @@ -336,7 +335,7 @@ private open class ProjectStoreImpl(project: ProjectImpl, private val pathMacroM val oldList = readonlyFiles.toTypedArray() readonlyFiles.clear() for (entry in oldList) { - errors = executeSave(entry.session, readonlyFiles, errors) + executeSave(entry.session, readonlyFiles, errors) } CompoundRuntimeException.throwIfNotEmpty(errors) @@ -345,8 +344,6 @@ private open class ProjectStoreImpl(project: ProjectImpl, private val pathMacroM dropUnableToSaveProjectNotification(project, getFilesList(readonlyFiles)) throw IComponentStore.SaveCancelledException() } - - return errors } protected open fun beforeSave(readonlyFiles: MutableList) { diff --git a/platform/platform-api/src/com/intellij/openapi/components/SettingsSavingComponent.java b/platform/platform-api/src/com/intellij/openapi/components/SettingsSavingComponent.java index 0acb0410dcba..aeeb3c145906 100644 --- a/platform/platform-api/src/com/intellij/openapi/components/SettingsSavingComponent.java +++ b/platform/platform-api/src/com/intellij/openapi/components/SettingsSavingComponent.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2018 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.components; import com.intellij.openapi.application.Application; @@ -21,7 +7,6 @@ import com.intellij.openapi.application.Application; * Component or service which implements this interfaces will be asked to save ({@link #save}) custom settings (in their own custom way) * when {@link Application#saveSettings()} (for Application level components) or {@link com.intellij.openapi.project.Project#save()} * (for Project level components) is invoked. - * @see BaseComponent */ public interface SettingsSavingComponent { void save();