diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JVMNameUtil.java b/java/debugger/impl/src/com/intellij/debugger/engine/JVMNameUtil.java index 85d181a4b20b..6d7192e8c63f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JVMNameUtil.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JVMNameUtil.java @@ -476,10 +476,16 @@ public class JVMNameUtil { @Nullable public static String getClassVMName(@Nullable PsiClass containingClass) { - if (containingClass == null) return null; + // no support for local classes for now + if (containingClass == null || PsiUtil.isLocalClass(containingClass)) return null; if (containingClass instanceof PsiAnonymousClass) { - return getClassVMName(PsiTreeUtil.getParentOfType(containingClass, PsiClass.class)) + - JavaAnonymousClassesHelper.getName((PsiAnonymousClass)containingClass); + String parentName = getClassVMName(PsiTreeUtil.getParentOfType(containingClass, PsiClass.class)); + if (parentName == null) { + return null; + } + else { + return parentName + JavaAnonymousClassesHelper.getName((PsiAnonymousClass)containingClass); + } } return ClassUtil.getJVMClassName(containingClass); } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java index 6ec3eefddb17..e72a8cea5884 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java @@ -213,8 +213,8 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio } private PsiElement remapElement(PsiElement element) { - PsiClass aClass = getEnclosingClass(element); - if (!Comparing.equal(myExpectedClassName, JVMNameUtil.getClassVMName(aClass))) { + String name = JVMNameUtil.getClassVMName(getEnclosingClass(element)); + if (name != null && !name.equals(myExpectedClassName)) { return null; } PsiElement method = DebuggerUtilsEx.getContainingMethod(element); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectConfigurable.java index 5d0670093a99..b6c53f1ca769 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectConfigurable.java @@ -25,6 +25,7 @@ import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.fileChooser.FileChooserFactory; import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.project.ex.ProjectEx; @@ -224,35 +225,39 @@ public class ProjectConfigurable extends ProjectStructureElementConfigurable 0) { - try { - canonicalPath = FileUtil.resolveShortWindowsName(canonicalPath); - } - catch (IOException e) { - //file doesn't exist yet - } - canonicalPath = FileUtil.toSystemIndependentName(canonicalPath); - compilerProjectExtension.setCompilerOutputUrl(VfsUtilCore.pathToUrl(canonicalPath)); - } - else { - compilerProjectExtension.setCompilerOutputPointer(null); - } + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + // set the output path first so that handlers of RootsChanged event sent after JDK is set + // would see the updated path + String canonicalPath = myProjectCompilerOutput.getText(); + if (canonicalPath != null && canonicalPath.length() > 0) { + try { + canonicalPath = FileUtil.resolveShortWindowsName(canonicalPath); + } + catch (IOException e) { + //file doesn't exist yet + } + canonicalPath = FileUtil.toSystemIndependentName(canonicalPath); + compilerProjectExtension.setCompilerOutputUrl(VfsUtilCore.pathToUrl(canonicalPath)); + } + else { + compilerProjectExtension.setCompilerOutputPointer(null); + } - LanguageLevelProjectExtension extension = LanguageLevelProjectExtension.getInstance(myProject); - extension.setLanguageLevel(myLanguageLevelCombo.getSelectedLevel()); - extension.setDefault(myLanguageLevelCombo.isDefault()); - myProjectJdkConfigurable.apply(); + LanguageLevelProjectExtension extension = LanguageLevelProjectExtension.getInstance(myProject); + extension.setLanguageLevel(myLanguageLevelCombo.getSelectedLevel()); + extension.setDefault(myLanguageLevelCombo.isDefault()); + myProjectJdkConfigurable.apply(); - if (myProjectName != null) { - ((ProjectEx)myProject).setProjectName(myProjectName.getText().trim()); - if (myDetailsComponent != null) myDetailsComponent.setText(getBannerSlogan()); - } + if (myProjectName != null) { + ((ProjectEx)myProject).setProjectName(myProjectName.getText().trim()); + if (myDetailsComponent != null) myDetailsComponent.setText(getBannerSlogan()); + } + } + }); } }); } diff --git a/java/testFramework/src/com/intellij/debugger/ExecutionWithDebuggerToolsTestCase.java b/java/testFramework/src/com/intellij/debugger/ExecutionWithDebuggerToolsTestCase.java index 19094ce1d354..e5501e20b062 100644 --- a/java/testFramework/src/com/intellij/debugger/ExecutionWithDebuggerToolsTestCase.java +++ b/java/testFramework/src/com/intellij/debugger/ExecutionWithDebuggerToolsTestCase.java @@ -144,7 +144,7 @@ public abstract class ExecutionWithDebuggerToolsTestCase extends ExecutionTestCa } catch (AssertionError e) { addException(e); - paused(suspendContext); + resume(suspendContext); } if (myScriptRunnables.isEmpty()) { diff --git a/platform/bootstrap/src/com/intellij/idea/Main.java b/platform/bootstrap/src/com/intellij/idea/Main.java index 6e45261447ec..17dccd320b5b 100644 --- a/platform/bootstrap/src/com/intellij/idea/Main.java +++ b/platform/bootstrap/src/com/intellij/idea/Main.java @@ -143,25 +143,28 @@ public class Main { return args.length > 0 && Comparing.strEqual(args[0], "traverseUI"); } - private static boolean checkBundledJava(File java) throws IOException { + private static boolean checkBundledJava(File java) throws Exception { String[] command = new String[]{java.getPath(), "-version"}; try { Process process = Runtime.getRuntime().exec(command); String line = (new BufferedReader(new InputStreamReader(process.getErrorStream()))).readLine(); if (line != null && (line.toLowerCase().startsWith("java version") || (line.toLowerCase().startsWith("openjdk version")))){ - String[] javaVersion = line.split("\\."); - int i = 1; - if (javaVersion.length > i && Integer.parseInt(javaVersion[i]) > 5) { - return true; + int pos = line.indexOf('.'); + if (pos > 0){ + int majorVersion = Integer.parseInt(line.substring(pos-1, pos)); + int minorVersion = Integer.parseInt(line.substring(pos+1, pos+2)); + if (majorVersion > 1 || minorVersion > 5) { + return true; + } } } - } catch (IOException e) { + } catch (Exception e) { System.out.println("updater: the java: " + command[0] + " is invalid."); } return false; } - private static String getBundledJava(String javaHome) throws IOException { + private static String getBundledJava(String javaHome) throws Exception { String javaHomeCopy = System.getProperty("user.home") + "/." + System.getProperty("idea.paths.selector") + "/restart/jre"; File javaCopy = SystemInfoRt.isWindows ? new File(javaHomeCopy + "/bin/java.exe") : new File(javaHomeCopy + "/bin/java"); if (javaCopy != null && javaCopy.isFile() && checkBundledJava(javaCopy)) { @@ -177,7 +180,7 @@ public class Main { return javaHome; } - private static String getJava() throws IOException { + private static String getJava() throws Exception { String javaHome = System.getProperty("java.home"); if (javaHome.toLowerCase().startsWith(PathManager.getHomePath().toLowerCase())) { System.out.println("Updater: uses bundled java."); @@ -186,7 +189,7 @@ public class Main { return javaHome + "/bin/java"; } - private static void installPatch() throws IOException { + private static void installPatch() throws Exception { String platform = System.getProperty(PLATFORM_PREFIX_PROPERTY, "idea"); String patchFileName = ("jetbrains.patch.jar." + platform).toLowerCase(Locale.US); String tempDir = System.getProperty("java.io.tmpdir"); diff --git a/platform/configuration-store-impl/src/ApplicationStoreImpl.kt b/platform/configuration-store-impl/src/ApplicationStoreImpl.kt new file mode 100644 index 000000000000..daaed3aa56fa --- /dev/null +++ b/platform/configuration-store-impl/src/ApplicationStoreImpl.kt @@ -0,0 +1,90 @@ +/* + * Copyright 2000-2015 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. + */ +package com.intellij.configurationStore + +import com.intellij.application.options.PathMacrosImpl +import com.intellij.openapi.application.PathManager +import com.intellij.openapi.application.impl.ApplicationImpl +import com.intellij.openapi.components.PathMacroManager +import com.intellij.openapi.components.StateStorage +import com.intellij.openapi.components.StateStorageOperation +import com.intellij.openapi.components.StoragePathMacros +import com.intellij.openapi.components.impl.BasePathMacroManager +import com.intellij.openapi.components.impl.stores.DirectoryStorageData +import com.intellij.openapi.components.impl.stores.StateStorageManager +import com.intellij.openapi.components.impl.stores.StorageData +import com.intellij.openapi.util.NamedJDOMExternalizable +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.openapi.vfs.VfsUtil + +class ApplicationPathMacroManager : BasePathMacroManager(null) + +class ApplicationStoreImpl(private val application: ApplicationImpl, pathMacroManager: PathMacroManager) : ComponentStoreImpl() { + private val stateStorageManager: StateStorageManager + + companion object { + private val DEFAULT_STORAGE_SPEC = "${StoragePathMacros.APP_CONFIG}/${PathManager.DEFAULT_OPTIONS_FILE_NAME}${DirectoryStorageData.DEFAULT_EXT}" + } + + init { + stateStorageManager = object : StateStorageManagerImpl(pathMacroManager.createTrackingSubstitutor(), "application", application, application.getPicoContainer()) { + private var configDirectoryRefreshed = false + + override fun createStorageTopicListener() = application.getMessageBus().syncPublisher(StateStorage.STORAGE_TOPIC) + + override fun createStorageData(fileSpec: String, filePath: String) = StorageData(rootTagName) + + override fun getOldStorageSpec(component: Any, componentName: String, operation: StateStorageOperation): String? { + if (component is NamedJDOMExternalizable) { + return "${StoragePathMacros.APP_CONFIG}/${component.getExternalFileName()}${DirectoryStorageData.DEFAULT_EXT}" + } + else { + return DEFAULT_STORAGE_SPEC + } + } + + override fun getMacroSubstitutor(fileSpec: String) = if (fileSpec == "${StoragePathMacros.APP_CONFIG}/${PathMacrosImpl.EXT_FILE_NAME}${DirectoryStorageData.DEFAULT_EXT}") null else super.getMacroSubstitutor(fileSpec) + + override fun isUseXmlProlog() = false + + override fun beforeFileBasedStorageCreate() { + if (configDirectoryRefreshed || (!application.isUnitTestMode() && !application.isDispatchThread())) { + return + } + + try { + val configPath = expandMacros(StoragePathMacros.ROOT_CONFIG) + if (configPath == StoragePathMacros.ROOT_CONFIG) { + LOG.warn("Macros ROOT_CONFIG is not defined") + return + } + + val configDir = LocalFileSystem.getInstance().refreshAndFindFileByPath(configPath) + if (configDir != null) { + VfsUtil.markDirtyAndRefresh(false, true, true, configDir) + } + } + finally { + configDirectoryRefreshed = true + } + } + } + } + + override fun getMessageBus() = application.getMessageBus() + + override fun getStateStorageManager() = stateStorageManager +} diff --git a/platform/configuration-store-impl/src/BaseFileConfigurableStoreImpl.kt b/platform/configuration-store-impl/src/BaseFileConfigurableStoreImpl.kt new file mode 100644 index 000000000000..853fc9c43f11 --- /dev/null +++ b/platform/configuration-store-impl/src/BaseFileConfigurableStoreImpl.kt @@ -0,0 +1,76 @@ +/* + * Copyright 2000-2015 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. + */ +package com.intellij.configurationStore + +import com.intellij.openapi.components.PathMacroManager +import com.intellij.openapi.components.PathMacroSubstitutor +import com.intellij.openapi.components.impl.stores.StateStorageManager +import com.intellij.openapi.components.impl.stores.StorageData +import org.jdom.Element +import kotlin.properties.Delegates + +abstract class BaseFileConfigurableStoreImpl(protected val pathMacroManager: PathMacroManager) : ComponentStoreImpl() { + val storageManager by Delegates.lazy { createStorageManager() } + + override fun getStateStorageManager() = storageManager + + override fun getPathMacroManagerForDefaults() = pathMacroManager + + protected abstract fun createStorageManager(): StateStorageManager +} + +open class ProjectStorageData : StorageData { + companion object { + val CURRENT_FORMAT_VERSION = 4 + val VERSION_OPTION: String = "version" + } + + private var version = CURRENT_FORMAT_VERSION + + constructor(rootElementName: String) : super(rootElementName) { + } + + protected constructor(storageData: ProjectStorageData) : super(storageData) { + } + + override fun load(rootElement: Element, pathMacroSubstitutor: PathMacroSubstitutor?, intern: Boolean) { + super.load(rootElement, pathMacroSubstitutor, intern) + + version = rootElement.getAttributeValue(VERSION_OPTION)?.toInt() ?: CURRENT_FORMAT_VERSION + } + + override fun save(newLiveStates: Map): Element { + var root = super.save(newLiveStates) + if (root == null) { + root = Element(myRootElementName) + } + writeOptions(root, Integer.toString(version)) + return root + } + + override fun clone() = ProjectStorageData(this) + + protected open fun writeOptions(root: Element, versionString: String) { + root.setAttribute(VERSION_OPTION, "4") + } + + override fun getChangedComponentNames(newStorageData: StorageData, substitutor: PathMacroSubstitutor?): Set? { + if (version != (newStorageData as ProjectStorageData).version) { + return null + } + return super.getChangedComponentNames(newStorageData, substitutor) + } +} diff --git a/platform/configuration-store-impl/src/ComponentStoreImpl.kt b/platform/configuration-store-impl/src/ComponentStoreImpl.kt new file mode 100644 index 000000000000..ce0fe478346a --- /dev/null +++ b/platform/configuration-store-impl/src/ComponentStoreImpl.kt @@ -0,0 +1,494 @@ +/* + * Copyright 2000-2015 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. + */ +package com.intellij.configurationStore + +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.PathManager +import com.intellij.openapi.application.ReadAction +import com.intellij.openapi.application.WriteAction +import com.intellij.openapi.application.ex.DecodeDefaultsUtil +import com.intellij.openapi.components.* +import com.intellij.openapi.components.StateStorage.SaveSession +import com.intellij.openapi.components.StateStorageChooserEx.Resolution +import com.intellij.openapi.components.impl.ComponentManagerImpl +import com.intellij.openapi.components.impl.stores.* +import com.intellij.openapi.components.impl.stores.StateStorageManager.ExternalizationSession +import com.intellij.openapi.components.store.ReadOnlyModificationException +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.progress.ProcessCanceledException +import com.intellij.openapi.project.Project +import com.intellij.openapi.util +import com.intellij.openapi.util.* +import com.intellij.openapi.util.Pair +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess +import com.intellij.util.ArrayUtilRt +import com.intellij.util.ReflectionUtil +import com.intellij.util.SmartList +import com.intellij.util.containers.MultiMap +import com.intellij.util.containers.SmartHashSet +import com.intellij.util.lang.CompoundRuntimeException +import com.intellij.util.messages.MessageBus +import com.intellij.util.xmlb.JDOMXIncluder +import gnu.trove.THashMap +import org.jdom.Element +import org.jdom.JDOMException +import org.jetbrains.annotations.TestOnly +import java.io.File +import java.io.IOException +import java.util.Arrays +import java.util.Collections +import java.util.Comparator +import java.util.LinkedHashSet +import java.util.concurrent.CopyOnWriteArrayList +import kotlin.reflect.jvm.java + +private val LOG = Logger.getInstance(javaClass()) + +public abstract class ComponentStoreImpl : IComponentStore { + private val myComponents = Collections.synchronizedMap(THashMap()) + private val mySettingsSavingComponents = CopyOnWriteArrayList() + + protected open val defaultStorageChooser: StateStorageChooser>? = null + + override fun initComponent(component: Any, service: Boolean) { + if (component is SettingsSavingComponent) { + mySettingsSavingComponents.add(component) + } + + if (!(component is JDOMExternalizable || component is PersistentStateComponent<*>)) { + return + } + + val token = ReadAction.start() + try { + val componentNameIfStateExists: String? + if (component is PersistentStateComponent<*>) { + componentNameIfStateExists = initPersistentComponent(component, null, false) + } + else { + componentNameIfStateExists = initJdomExternalizable(component as JDOMExternalizable) + } + + // if not service, so, component manager will check it later for all components + if (componentNameIfStateExists != null && service) { + val project = getProject() + val app = ApplicationManager.getApplication() + if (project != null && !app.isHeadlessEnvironment() && !app.isUnitTestMode() && project.isInitialized()) { + val substitutor = getStateStorageManager().getMacroSubstitutor() + if (substitutor != null) { + StorageUtil.notifyUnknownMacros(substitutor, project, componentNameIfStateExists) + } + } + } + } + catch (e: StateStorageException) { + throw e + } + catch (e: ProcessCanceledException) { + throw e + } + catch (e: Exception) { + LOG.error(e) + } + finally { + token.finish() + } + } + + override fun save(readonlyFiles: MutableList>) { + val externalizationSession = if (myComponents.isEmpty()) null else getStateStorageManager().startExternalization() + if (externalizationSession != null) { + val names = ArrayUtilRt.toStringArray(myComponents.keySet()) + Arrays.sort(names) + for (name in names) { + commitComponent(externalizationSession, myComponents.get(name)!!, name) + } + } + + var errors: MutableList? = null + for (settingsSavingComponent in mySettingsSavingComponents) { + try { + settingsSavingComponent.save() + } + catch (e: Throwable) { + if (errors == null) { + errors = SmartList() + } + errors.add(e) + } + + } + + errors = doSave(externalizationSession?.createSaveSessions(), readonlyFiles, errors) + CompoundRuntimeException.doThrow(errors) + } + + override TestOnly fun saveApplicationComponent(component: Any) { + val externalizationSession = getStateStorageManager().startExternalization() ?: return + + commitComponent(externalizationSession, component, null) + val sessions = externalizationSession.createSaveSessions() + if (sessions.isEmpty()) { + return + } + + val file: File + val state = StoreUtil.getStateSpec(component.javaClass) + if (state != null) { + file = File(getStateStorageManager().expandMacros(findNonDeprecated(state.storages).file)) + } + else if (component is ExportableApplicationComponent && component is NamedJDOMExternalizable) { + file = PathManager.getOptionsFile(component) + } + else { + throw AssertionError("${component.javaClass} doesn't have @State annotation and doesn't implement ExportableApplicationComponent") + } + + val token = WriteAction.start() + try { + VfsRootAccess.allowRootAccess(file.getAbsolutePath()) + CompoundRuntimeException.doThrow(doSave(sessions, arrayListOf(), null)) + } + finally { + try { + VfsRootAccess.disallowRootAccess(file.getAbsolutePath()) + } + finally { + token.finish() + } + } + } + + private fun commitComponent(externalizationSession: ExternalizationSession, component: Any, componentName: String?) { + if (component is PersistentStateComponent<*>) { + commitPersistentComponent(component, externalizationSession, componentName) + } + else if (component is JDOMExternalizable) { + externalizationSession.setStateInOldStorage(component, componentName ?: ComponentManagerImpl.getComponentName(component), component) + } + } + + protected open fun doSave(saveSessions: List?, readonlyFiles: MutableList>, prevErrors: MutableList?): MutableList? { + var errors = prevErrors + if (saveSessions != null) { + for (session in saveSessions) { + errors = executeSave(session, readonlyFiles, prevErrors) + } + } + return errors + } + + private fun commitPersistentComponent(component: PersistentStateComponent, session: ExternalizationSession, componentName: String?) { + val state = component.getState() + if (state != null) { + val storageSpecs = getComponentStorageSpecs(component, StoreUtil.getStateSpec(component), StateStorageOperation.WRITE) + session.setState(storageSpecs, component, componentName ?: StoreUtil.getComponentName(component), state) + } + } + + private fun initJdomExternalizable(component: JDOMExternalizable): String? { + val componentName = ComponentManagerImpl.getComponentName(component) + doAddComponent(componentName, component) + + if (optimizeTestLoading()) { + return null + } + + loadJdomDefaults(component, componentName) + + val stateStorage = getStateStorageManager().getOldStorage(component, componentName, StateStorageOperation.READ) ?: return null + val element = stateStorage.getState(component, componentName, javaClass(), null) ?: return null + try { + if (LOG.isDebugEnabled()) { + LOG.debug("Loading configuration for " + component.javaClass) + } + component.readExternal(element) + } + catch (e: InvalidDataException) { + LOG.error(e) + return null + } + + + return componentName + } + + private fun doAddComponent(componentName: String, component: Any) { + val existing = myComponents.get(componentName) + if (existing != null && existing !== component) { + LOG.error("Conflicting component name '" + componentName + "': " + existing.javaClass + " and " + component.javaClass) + } + myComponents.put(componentName, component) + } + + private fun loadJdomDefaults(component: JDOMExternalizable, componentName: String) { + try { + val defaultState = getDefaultState(component, componentName, javaClass()) + if (defaultState != null) { + component.readExternal(defaultState) + } + } + catch (e: Exception) { + LOG.error("Cannot load defaults for " + component.javaClass, e) + } + + } + + protected open fun getProject(): Project? = null + + private fun initPersistentComponent(component: PersistentStateComponent, changedStorages: Set?, reloadData: Boolean): String? { + val stateSpec = StoreUtil.getStateSpec(component) + val name = stateSpec.name + if (changedStorages == null || !reloadData) { + doAddComponent(name, component) + } + if (optimizeTestLoading()) { + return null + } + + val stateClass = ComponentSerializationUtil.getStateClass(component.javaClass) + if (!stateSpec.defaultStateAsResource && LOG.isDebugEnabled() && getDefaultState(component, name, stateClass) != null) { + LOG.error(name + " has default state, but not marked to load it") + } + + var state = if (stateSpec.defaultStateAsResource) getDefaultState(component, name, stateClass) else null + val storageSpecs = getComponentStorageSpecs(component, stateSpec, StateStorageOperation.READ) + val stateStorageChooser = component as? StateStorageChooserEx + for (storageSpec in storageSpecs) { + val resolution = if (stateStorageChooser == null) Resolution.DO else stateStorageChooser.getResolution(storageSpec, StateStorageOperation.READ) + if (resolution === Resolution.SKIP) { + continue + } + + val stateStorage = getStateStorageManager().getStateStorage(storageSpec) + if (stateStorage != null) { + var forcedState = false + if (!stateStorage.hasState(component, name, stateClass, reloadData)) { + forcedState = changedStorages != null && changedStorages.contains(stateStorage) + if (!forcedState) { + continue + } + } + + state = stateStorage.getState(component, name, stateClass, state) + if (state == null && forcedState) { + // state will be null if file deleted + // we must create empty (initial) state to reinit component + state = DefaultStateSerializer.deserializeState(Element("state"), stateClass, null) + } + break + } + } + + if (state != null) { + component.loadState(state) + } + + return name + } + + protected open fun getPathMacroManagerForDefaults(): PathMacroManager? = null + + protected fun getDefaultState(component: Any, componentName: String, stateClass: Class): T? { + val url = DecodeDefaultsUtil.getDefaults(component, componentName) ?: return null + try { + val documentElement = JDOMXIncluder.resolve(JDOMUtil.loadDocument(url), url.toExternalForm()).detachRootElement() + getPathMacroManagerForDefaults()?.expandPaths(documentElement) + return DefaultStateSerializer.deserializeState(documentElement, stateClass, null) + } + catch (e: IOException) { + throw StateStorageException("Error loading state from " + url, e) + } + catch (e: JDOMException) { + throw StateStorageException("Error loading state from " + url, e) + } + + } + + protected open fun getComponentStorageSpecs(component: PersistentStateComponent, stateSpec: State, operation: StateStorageOperation): Array { + val storages = stateSpec.storages + if (storages.size() == 1 || component is StateStorageChooserEx) { + return storages + } + assert(!storages.isEmpty()) + + var storageChooserClass = stateSpec.storageChooser.java + if (storageChooserClass != javaClass>()) { + @suppress("UNCHECKED_CAST") + val stateStorageChooser: StateStorageChooser = ReflectionUtil.newInstance(stateSpec.storageChooser.java as Class>) + return stateStorageChooser.selectStorages(storages, component, operation) + } + + val defaultChooser = defaultStorageChooser + if (defaultChooser != null) { + return defaultChooser.selectStorages(storages, component, operation) + } + + var actualStorageCount = 0 + for (storage in storages) { + if (!storage.deprecated) { + actualStorageCount++ + } + } + + if (actualStorageCount > 1) { + LOG.error("State chooser not specified for: " + component.javaClass) + } + + if (!storages[0].deprecated) { + var othersAreDeprecated = true + for (i in 1..storages.size() - 1) { + if (!storages[i].deprecated) { + othersAreDeprecated = false + break + } + } + + if (othersAreDeprecated) { + return storages + } + } + + val sorted = Arrays.copyOf(storages, storages.size()) + Arrays.sort(sorted, object : Comparator { + override fun compare(o1: Storage, o2: Storage): Int { + val w1 = if (o1.deprecated) 1 else 0 + val w2 = if (o2.deprecated) 1 else 0 + return w1 - w2 + } + }) + return sorted + } + + protected open fun optimizeTestLoading(): Boolean = false + + override fun isReloadPossible(componentNames: Set): Boolean { + for (componentName in componentNames) { + val component = myComponents.get(componentName) + if (component != null && (component !is PersistentStateComponent<*> || !StoreUtil.getStateSpec(component).reloadable)) { + return false + } + } + + return true + } + + override fun getNotReloadableComponents(componentNames: Collection): Collection { + var notReloadableComponents: MutableSet? = null + for (componentName in componentNames) { + val component = myComponents.get(componentName) + if (component != null && (component !is PersistentStateComponent<*> || !StoreUtil.getStateSpec(component).reloadable)) { + if (notReloadableComponents == null) { + notReloadableComponents = LinkedHashSet() + } + notReloadableComponents.add(componentName) + } + } + return if (notReloadableComponents == null) emptySet() else notReloadableComponents + } + + override fun reinitComponents(componentNames: Set, reloadData: Boolean) { + reinitComponents(componentNames, emptySet(), emptySet()) + } + + override fun reinitComponent(componentName: String, changedStorages: Set): Boolean { + val component = myComponents.get(componentName) as PersistentStateComponent<*>? + if (component == null) { + return false + } + else { + val changedStoragesEmpty = changedStorages.isEmpty() + initPersistentComponent(component, if (changedStoragesEmpty) null else changedStorages, changedStoragesEmpty) + return true + } + } + + protected abstract fun getMessageBus(): MessageBus + + override fun reload(changedStorages: MultiMap): Collection? { + if (changedStorages.isEmpty()) { + return emptySet() + } + + val componentNames = SmartHashSet() + for (storage in changedStorages.keySet()) { + try { + // we must update (reload in-memory storage data) even if non-reloadable component will be detected later + // not saved -> user does own modification -> new (on disk) state will be overwritten and not applied + storage.analyzeExternalChangesAndUpdateIfNeed(changedStorages.get(storage), componentNames) + } + catch (e: Throwable) { + LOG.error(e) + } + + } + + if (componentNames.isEmpty()) { + return emptySet() + } + + val notReloadableComponents = getNotReloadableComponents(componentNames) + reinitComponents(componentNames, notReloadableComponents, changedStorages.keySet()) + return if (notReloadableComponents.isEmpty()) null else notReloadableComponents + } + + // used in settings repository plugin + public fun reinitComponents(componentNames: Set, notReloadableComponents: Collection, changedStorages: Set) { + val messageBus = getMessageBus() + messageBus.syncPublisher(BatchUpdateListener.TOPIC).onBatchUpdateStarted() + try { + for (componentName in componentNames) { + if (!notReloadableComponents.contains(componentName)) { + reinitComponent(componentName, changedStorages) + } + } + } + finally { + messageBus.syncPublisher(BatchUpdateListener.TOPIC).onBatchUpdateFinished() + } + } + + companion object { + private fun findNonDeprecated(storages: Array): Storage { + for (storage in storages) { + if (!storage.deprecated) { + return storage + } + } + throw AssertionError("All storages are deprecated") + } + + protected fun executeSave(session: SaveSession, readonlyFiles: MutableList>, previousErrors: MutableList?): MutableList? { + var errors = previousErrors + try { + session.save() + } + catch (e: ReadOnlyModificationException) { + LOG.warn(e) + readonlyFiles.add(util.Pair.create(if (e.getSession() == null) session else e.getSession(), e.getFile())) + } + catch (e: Exception) { + if (errors == null) { + errors = SmartList() + } + errors.add(e) + } + + return errors + } + } +} diff --git a/platform/configuration-store-impl/src/DefaultProjectStoreImpl.kt b/platform/configuration-store-impl/src/DefaultProjectStoreImpl.kt new file mode 100644 index 000000000000..c3bd5fd1f737 --- /dev/null +++ b/platform/configuration-store-impl/src/DefaultProjectStoreImpl.kt @@ -0,0 +1,81 @@ +/* + * Copyright 2000-2015 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. + */ +package com.intellij.configurationStore + +import com.intellij.openapi.components.* +import com.intellij.openapi.components.impl.stores.FileBasedStorage +import com.intellij.openapi.components.impl.stores.StateStorageManager +import com.intellij.openapi.components.impl.stores.StreamProvider +import com.intellij.openapi.project.impl.ProjectImpl +import com.intellij.openapi.project.impl.ProjectManagerImpl +import com.intellij.openapi.util.Couple +import com.intellij.util.containers.ContainerUtil +import org.jdom.Element + +class DefaultProjectStoreImpl(project: ProjectImpl, private val projectManager: ProjectManagerImpl, pathMacroManager: PathMacroManager) : ProjectStoreImpl(project, pathMacroManager) { + fun getStateCopy(): Element? { + val element = projectManager.getDefaultProjectRootElement() + return element?.clone() + } + + override protected fun createStorageManager(): StateStorageManager { + val storage = DefaultProjectStorage(this, pathMacroManager, projectManager) + //noinspection deprecation + return object : StateStorageManager { + override fun addMacro(macro: String, expansion: String) = throw UnsupportedOperationException("Method addMacro not implemented in " + javaClass) + + override fun getMacroSubstitutor() = null + + override fun getStateStorage(storageSpec: Storage) = storage + + override fun getStateStorage(fileSpec: String, roamingType: RoamingType) = storage + + override fun getCachedFileStateStorages(changed: Collection, deleted: Collection): Couple> = Couple(emptyList(), emptyList()) + + override fun clearStateStorage(file: String) { + } + + override fun startExternalization(): StateStorageManager.ExternalizationSession? { + val externalizationSession = storage.startExternalization() + return if (externalizationSession == null) null else MyExternalizationSession(externalizationSession) + } + + override fun expandMacros(file: String) = throw UnsupportedOperationException("Method expandMacros not implemented in " + javaClass) + + override fun collapseMacros(path: String) = throw UnsupportedOperationException("Method collapseMacros not implemented in " + javaClass) + + override fun getOldStorage(component: Any, componentName: String, operation: StateStorageOperation) = storage + + override fun setStreamProvider(streamProvider: StreamProvider?) = throw UnsupportedOperationException("Method setStreamProvider not implemented in " + javaClass) + + override fun getStreamProvider() = throw UnsupportedOperationException("Method getStreamProviders not implemented in " + javaClass) + + override fun getStorageFileNames() = throw UnsupportedOperationException("Method getStorageFileNames not implemented in " + javaClass) + } + } + + private class MyExternalizationSession(val externalizationSession: StateStorage.ExternalizationSession) : StateStorageManager.ExternalizationSession { + override fun setState(storageSpecs: Array, component: Any, componentName: String, state: Any) { + externalizationSession.setState(component, componentName, state, null) + } + + override fun setStateInOldStorage(component: Any, componentName: String, state: Any) { + externalizationSession.setState(component, componentName, state, null) + } + + override fun createSaveSessions() = ContainerUtil.createMaybeSingletonList(externalizationSession.createSaveSession()) + } +} diff --git a/platform/configuration-store-impl/src/ModuleFileData.kt b/platform/configuration-store-impl/src/ModuleFileData.kt new file mode 100644 index 000000000000..4d6973b93086 --- /dev/null +++ b/platform/configuration-store-impl/src/ModuleFileData.kt @@ -0,0 +1,97 @@ +/* + * Copyright 2000-2015 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. + */ +package com.intellij.configurationStore + +import com.intellij.openapi.components.PathMacroSubstitutor +import com.intellij.openapi.components.impl.stores.StorageData +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.OptionManager +import com.intellij.openapi.util.text.StringUtil +import org.jdom.Element +import java.util.TreeMap + +class ModuleFileData : ProjectStorageData, OptionManager { + private var options: TreeMap? = null + private val module: Module + + private var dirty = true + + override fun isDirty() = dirty + + public constructor(rootElementName: String, module: Module) : super(rootElementName) { + this.module = module + options = TreeMap() + } + + private constructor(storageData: ModuleFileData) : super(storageData) { + module = storageData.module + dirty = storageData.dirty + options = TreeMap(storageData.options) + } + + override fun load(rootElement: Element, pathMacroSubstitutor: PathMacroSubstitutor?, intern: Boolean) { + super.load(rootElement, pathMacroSubstitutor, intern) + + for (attribute in rootElement.getAttributes()) { + val name = attribute.getName() + if (name != ProjectStorageData.VERSION_OPTION && !StringUtil.isEmpty(name)) { + options!!.put(name, attribute.getValue()) + } + } + + dirty = false + } + + override fun writeOptions(root: Element, versionString: String) { + if (!options!!.isEmpty()) { + for (key in options!!.keySet()) { + val value = options!!.get(key) + if (value != null) { + root.setAttribute(key, value) + } + } + } + // need be last for compat reasons + super.writeOptions(root, versionString) + + dirty = false + } + + override fun clone() = ModuleFileData(this) + + override fun getChangedComponentNames(newStorageData: StorageData, substitutor: PathMacroSubstitutor?): Set? { + val data = newStorageData as ModuleFileData + if (options != data.options) { + return null + } + + return super.getChangedComponentNames(newStorageData, substitutor) + } + + override fun setOption(key: String, value: String) { + if (value != options!!.put(key, value)) { + dirty = true + } + } + + override fun clearOption(key: String) { + if (options!!.remove(key) != null) { + dirty = true + } + } + + override fun getOptionValue(key: String) = options!!.get(key) +} \ No newline at end of file diff --git a/platform/configuration-store-impl/src/ModuleStateStorageManager.kt b/platform/configuration-store-impl/src/ModuleStateStorageManager.kt new file mode 100644 index 000000000000..63baa6f6ed74 --- /dev/null +++ b/platform/configuration-store-impl/src/ModuleStateStorageManager.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2015 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. + */ +package com.intellij.configurationStore + +import com.intellij.openapi.components.StateStorage +import com.intellij.openapi.components.StateStorageOperation +import com.intellij.openapi.components.StoragePathMacros +import com.intellij.openapi.components.TrackingPathMacroSubstitutor +import com.intellij.openapi.module.Module +import com.intellij.util.containers.ContainerUtil + +class ModuleStateStorageManager(pathMacroManager: TrackingPathMacroSubstitutor, private val myModule: Module) : StateStorageManagerImpl(pathMacroManager, "module", myModule, myModule.getPicoContainer()) { + override fun createStorageData(fileSpec: String, filePath: String) = ModuleFileData(rootTagName, myModule) + + override fun startExternalization() = MyStateStorageManagerExternalizationSession(this) + + private class MyStateStorageManagerExternalizationSession(storageManager: StateStorageManagerImpl) : StateStorageManagerImpl.StateStorageManagerExternalizationSession(storageManager) { + override fun createSaveSessions(): List { + val storage = ContainerUtil.getFirstItem(storageManager.getCachedFileStorages(listOf(StoragePathMacros.MODULE_FILE))) + if (storage != null && storage.getStorageData().isDirty()) { + // force XmlElementStorageSaveSession creation + getExternalizationSession(storage) + } + return super.createSaveSessions() + } + } + + override fun getOldStorageSpec(component: Any, componentName: String, operation: StateStorageOperation) = StoragePathMacros.MODULE_FILE + + override fun createStorageTopicListener() = myModule.getProject().getMessageBus().syncPublisher(StateStorage.PROJECT_STORAGE_TOPIC) +} \ No newline at end of file diff --git a/platform/configuration-store-impl/src/ModuleStoreImpl.kt b/platform/configuration-store-impl/src/ModuleStoreImpl.kt new file mode 100644 index 000000000000..59cb995e8eed --- /dev/null +++ b/platform/configuration-store-impl/src/ModuleStoreImpl.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2015 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. + */ +package com.intellij.configurationStore + +import com.intellij.openapi.components.PathMacroManager +import com.intellij.openapi.module.Module +import com.intellij.openapi.project.ex.ProjectEx + +class ModuleStoreImpl(private val myModule: Module, pathMacroManager: PathMacroManager) : BaseFileConfigurableStoreImpl(pathMacroManager) { + override fun getProject() = myModule.getProject() + + override fun optimizeTestLoading() = (myModule.getProject() as ProjectEx).isOptimiseTestLoadSpeed() + + override fun getMessageBus() = myModule.getMessageBus() + + override fun createStorageManager() = ModuleStateStorageManager(pathMacroManager.createTrackingSubstitutor(), myModule) +} \ No newline at end of file diff --git a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/PlatformProjectStoreClassProvider.java b/platform/configuration-store-impl/src/PlatformProjectStoreClassProvider.kt similarity index 64% rename from platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/PlatformProjectStoreClassProvider.java rename to platform/configuration-store-impl/src/PlatformProjectStoreClassProvider.kt index b98bf9eccfd2..b1a94c0ab065 100644 --- a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/PlatformProjectStoreClassProvider.java +++ b/platform/configuration-store-impl/src/PlatformProjectStoreClassProvider.kt @@ -13,14 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.openapi.components.impl.stores; +package com.intellij.configurationStore -import com.intellij.openapi.project.impl.ProjectStoreClassProvider; -import org.jetbrains.annotations.NotNull; +import com.intellij.openapi.components.impl.stores.IComponentStore +import com.intellij.openapi.project.impl.ProjectStoreClassProvider -public class PlatformProjectStoreClassProvider implements ProjectStoreClassProvider { - @NotNull - public Class getProjectStoreClass(boolean isDefaultProject) { - return isDefaultProject ? DefaultProjectStoreImpl.class : ProjectStoreImpl.class; +class PlatformProjectStoreClassProvider : ProjectStoreClassProvider { + override fun getProjectStoreClass(isDefaultProject: Boolean): Class { + return if (isDefaultProject) javaClass() else javaClass() } } \ No newline at end of file diff --git a/platform/configuration-store-impl/src/ProjectStateStorageManager.kt b/platform/configuration-store-impl/src/ProjectStateStorageManager.kt new file mode 100644 index 000000000000..df4b432d981f --- /dev/null +++ b/platform/configuration-store-impl/src/ProjectStateStorageManager.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2015 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. + */ +package com.intellij.configurationStore + +import com.intellij.openapi.components.* +import com.intellij.openapi.project.impl.ProjectImpl +import org.jdom.Element + +class ProjectStateStorageManager(macroSubstitutor: TrackingPathMacroSubstitutor, private val project: ProjectImpl) : StateStorageManagerImpl(macroSubstitutor, "project", project, project.getPicoContainer()) { + override fun createStorageData(fileSpec: String, filePath: String) = ProjectStorageData(rootTagName) + + override fun getOldStorageSpec(component: Any, componentName: String, operation: StateStorageOperation): String? { + val workspace = project.isWorkspaceComponent(component.javaClass) + var fileSpec = if (workspace) StoragePathMacros.WORKSPACE_FILE else StoragePathMacros.PROJECT_FILE + val storage = getStateStorage(fileSpec, if (workspace) RoamingType.DISABLED else RoamingType.PER_USER) + if (operation === StateStorageOperation.READ && storage != null && workspace && !storage.hasState(component, componentName, javaClass(), false)) { + fileSpec = StoragePathMacros.PROJECT_FILE + } + return fileSpec + } + + override fun createStorageTopicListener() = project.getMessageBus().syncPublisher(StateStorage.PROJECT_STORAGE_TOPIC) +} \ No newline at end of file diff --git a/platform/configuration-store-impl/src/ProjectStoreImpl.kt b/platform/configuration-store-impl/src/ProjectStoreImpl.kt new file mode 100644 index 000000000000..fe5cd28830e6 --- /dev/null +++ b/platform/configuration-store-impl/src/ProjectStoreImpl.kt @@ -0,0 +1,376 @@ +/* + * Copyright 2000-2015 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. + */ +package com.intellij.configurationStore + +import com.intellij.ide.highlighter.ProjectFileType +import com.intellij.ide.highlighter.WorkspaceFileType +import com.intellij.notification.Notifications +import com.intellij.notification.NotificationsManager +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.ModalityState +import com.intellij.openapi.application.ReadAction +import com.intellij.openapi.components.* +import com.intellij.openapi.components.StateStorage.SaveSession +import com.intellij.openapi.components.impl.stores.* +import com.intellij.openapi.fileTypes.FileTypeManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.project.impl.ProjectImpl +import com.intellij.openapi.project.impl.ProjectManagerImpl.UnableToSaveProjectNotification +import com.intellij.openapi.util.Pair +import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.util.io.FileUtilRt +import com.intellij.openapi.util.text.StringUtil +import com.intellij.openapi.vfs.* +import com.intellij.util.PathUtilRt +import com.intellij.util.SmartList +import com.intellij.util.lang.CompoundRuntimeException +import java.io.BufferedReader +import java.io.File +import java.io.IOException +import java.io.InputStreamReader +import java.util.ArrayList + +open class ProjectStoreImpl(protected var myProject: ProjectImpl, pathMacroManager: PathMacroManager) : BaseFileConfigurableStoreImpl(pathMacroManager), IProjectStore { + // protected setter used in upsource + private var scheme = StorageScheme.DEFAULT + protected set + + private var presentableUrl: String? = null + + override fun getSubstitutors(): Array { + val substitutor = getStateStorageManager().getMacroSubstitutor() + return if (substitutor == null) emptyArray() else arrayOf(substitutor) + } + + override fun optimizeTestLoading() = myProject.isOptimiseTestLoadSpeed() + + override fun getProject() = myProject + + override fun setProjectFilePath(filePath: String) { + val stateStorageManager = getStateStorageManager() + val fs = LocalFileSystem.getInstance() + + val file = File(filePath) + if (isIprPath(file)) { + scheme = StorageScheme.DEFAULT + + stateStorageManager.addMacro(StoragePathMacros.PROJECT_FILE, filePath) + + val workspacePath = composeWsPath(filePath) + stateStorageManager.addMacro(StoragePathMacros.WORKSPACE_FILE, workspacePath) + + ApplicationManager.getApplication().invokeAndWait(object : Runnable { + override fun run() { + VfsUtil.markDirtyAndRefresh(false, true, false, fs.refreshAndFindFileByPath(filePath), fs.refreshAndFindFileByPath(workspacePath)) + } + }, ModalityState.defaultModalityState()) + } + else { + scheme = StorageScheme.DIRECTORY_BASED + + val dirStore = File(if (file.isDirectory()) file else file.getParentFile(), Project.DIRECTORY_STORE_FOLDER) + stateStorageManager.addMacro(StoragePathMacros.PROJECT_FILE, File(dirStore, "misc.xml").getPath()) + stateStorageManager.addMacro(StoragePathMacros.PROJECT_CONFIG_DIR, dirStore.getPath()) + + val workspace = File(dirStore, "workspace.xml") + stateStorageManager.addMacro(StoragePathMacros.WORKSPACE_FILE, workspace.getPath()) + if (!workspace.exists() && !file.isDirectory()) { + useOldWorkspaceContent(filePath, workspace) + } + + ApplicationManager.getApplication().invokeAndWait(object : Runnable { + override fun run() { + VfsUtil.markDirtyAndRefresh(false, true, true, fs.refreshAndFindFileByIoFile(dirStore)) + } + }, ModalityState.defaultModalityState()) + } + + presentableUrl = null + } + + override fun getProjectBaseDir(): VirtualFile? { + if (myProject.isDefault()) { + return null + } + val path = getProjectBasePath() ?: return null + return LocalFileSystem.getInstance().findFileByPath(path) + } + + override fun getProjectBasePath(): String? { + if (myProject.isDefault()) { + return null + } + + val path = getProjectFilePath() + if (!StringUtil.isEmptyOrSpaces(path)) { + return getBasePath(File(path)) + } + + //we are not yet initialized completely ("open directory", etc) + val storage = getStateStorageManager().getStateStorage(StoragePathMacros.PROJECT_FILE, RoamingType.PER_USER) + return if (storage is FileBasedStorage) getBasePath(storage.getFile()) else null + } + + private fun getBasePath(file: File) = if (scheme == StorageScheme.DEFAULT) file.getParent() else file.getParentFile()?.getParent() + + override fun getProjectName(): String { + if (scheme == StorageScheme.DIRECTORY_BASED) { + val baseDir = getProjectBaseDir() + assert(baseDir != null) { "scheme=$scheme project file=${getProjectFilePath()}" } + + val ideaDir = baseDir!!.findChild(Project.DIRECTORY_STORE_FOLDER) + if (ideaDir != null && ideaDir.isValid()) { + val nameFile = ideaDir.findChild(ProjectImpl.NAME_FILE) + if (nameFile != null && nameFile.isValid()) { + try { + val `in` = BufferedReader(InputStreamReader(nameFile.getInputStream(), CharsetToolkit.UTF8_CHARSET)) + try { + val name = `in`.readLine() + if (name != null && !name.isEmpty()) { + return name.trim() + } + } + finally { + `in`.close() + } + } + catch (ignored: IOException) { + } + + } + } + + return baseDir.getName().replace(":", "") + } + else { + var temp = PathUtilRt.getFileName((getProjectFileStorage() as FileBasedStorage).getFilePath()) + val fileType = FileTypeManager.getInstance().getFileTypeByFileName(temp) + if (fileType is ProjectFileType) { + temp = temp.substring(0, temp.length() - fileType.getDefaultExtension().length() - 1) + } + val i = temp.lastIndexOf(File.separatorChar) + if (i >= 0) { + temp = temp.substring(i + 1, temp.length() - i + 1) + } + return temp + } + } + + override fun getStorageScheme() = scheme + + override fun getPresentableUrl(): String? { + if (myProject.isDefault()) { + return null + } + if (presentableUrl == null) { + val url = if (scheme == StorageScheme.DIRECTORY_BASED) getProjectBasePath() else getProjectFilePath() + if (url != null) { + presentableUrl = FileUtil.toSystemDependentName(url) + } + } + return presentableUrl + } + + override fun getProjectFile() = if (myProject.isDefault()) null else (getProjectFileStorage() as FileBasedStorage).getVirtualFile() + + override fun getProjectFilePath() = if (myProject.isDefault()) "" else (getProjectFileStorage() as FileBasedStorage).getFilePath() + + // XmlElementStorage if default project, otherwise FileBasedStorage + private fun getProjectFileStorage() = getStateStorageManager().getStateStorage(StoragePathMacros.PROJECT_FILE, RoamingType.PER_USER) as XmlElementStorage + + override fun getWorkspaceFile(): VirtualFile? { + if (myProject.isDefault()) return null + val storage = getStateStorageManager().getStateStorage(StoragePathMacros.WORKSPACE_FILE, RoamingType.DISABLED) as FileBasedStorage? + assert(storage != null) + return storage!!.getVirtualFile() + } + + override fun getWorkspaceFilePath(): String? { + if (myProject.isDefault()) { + return null + } + return (getStateStorageManager().getStateStorage(StoragePathMacros.WORKSPACE_FILE, RoamingType.DISABLED) as FileBasedStorage?)!!.getFilePath() + } + + override fun loadProjectFromTemplate(defaultProject: ProjectImpl) { + defaultProject.save() + + val element = (defaultProject.getStateStore() as DefaultProjectStoreImpl).getStateCopy() + if (element != null) { + getProjectFileStorage().setDefaultState(element) + } + } + + override fun createStorageManager(): StateStorageManager = ProjectStateStorageManager(pathMacroManager.createTrackingSubstitutor(), myProject) + + override fun doSave(saveSessions: List?, readonlyFiles: MutableList>, prevErrors: MutableList?): MutableList? { + var errors = prevErrors + beforeSave(readonlyFiles) + + super.doSave(saveSessions, readonlyFiles, errors) + + val notifications = NotificationsManager.getNotificationsManager().getNotificationsOfType(javaClass(), myProject) + if (readonlyFiles.isEmpty()) { + for (notification in notifications) { + notification.expire() + } + return errors + } + + if (!notifications.isEmpty()) { + throw IComponentStore.SaveCancelledException() + } + + val status: ReadonlyStatusHandler.OperationStatus + val token = ReadAction.start() + try { + status = ReadonlyStatusHandler.getInstance(myProject).ensureFilesWritable(*getFilesList(readonlyFiles)) + } + finally { + token.finish() + } + + if (status.hasReadonlyFiles()) { + dropUnableToSaveProjectNotification(myProject, status.getReadonlyFiles()) + throw IComponentStore.SaveCancelledException() + } + val oldList = ArrayList(readonlyFiles) + readonlyFiles.clear() + for (entry in oldList) { + errors = ComponentStoreImpl.executeSave(entry.first, readonlyFiles, errors) + } + + if (errors != null) { + CompoundRuntimeException.doThrow(errors) + } + + if (!readonlyFiles.isEmpty()) { + dropUnableToSaveProjectNotification(myProject, getFilesList(readonlyFiles)) + throw IComponentStore.SaveCancelledException() + } + + return errors + } + + protected open fun beforeSave(readonlyFiles: List>) { + } + + private var _defaultStorageChooser: StateStorageChooser>? = null + + override val defaultStorageChooser: StateStorageChooser>? + get() { + if (_defaultStorageChooser == null) { + _defaultStorageChooser = DefaultStorageChooser(scheme) + } + return _defaultStorageChooser + } + + override fun getMessageBus() = myProject.getMessageBus() + + override fun getComponentStorageSpecs(component: PersistentStateComponent, stateSpec: State, operation: StateStorageOperation): Array { + // if we create project from default, component state written not to own storage file, but to project file, + // we don't have time to fix it properly, so, ancient hack restored. + val result = super.getComponentStorageSpecs(component, stateSpec, operation) + // don't add fake storage if project file storage already listed, otherwise data will be deleted on write (because of "deprecated") + for (storage in result) { + if (storage.file == StoragePathMacros.PROJECT_FILE) { + return result + } + } + return Array(result.size() + 1) { if (it == result.size()) DEFAULT_STORAGE_ANNOTATION else result[it] } + } + + companion object { + private val DEFAULT_STORAGE_ANNOTATION = DefaultStorageAnnotation() + + private fun isIprPath(file: File) = FileUtilRt.extensionEquals(file.getName(), ProjectFileType.DEFAULT_EXTENSION) + + private fun composeWsPath(filePath: String): String { + val lastDot = filePath.lastIndexOf('.') + val filePathWithoutExt = if (lastDot > 0) filePath.substring(0, lastDot) else filePath + return "$filePathWithoutExt${WorkspaceFileType.DOT_DEFAULT_EXTENSION}" + } + + private fun useOldWorkspaceContent(filePath: String, ws: File) { + val oldWs = File(composeWsPath(filePath)) + if (!oldWs.exists()) { + return + } + + try { + FileUtil.copyContent(oldWs, ws) + } + catch (e: IOException) { + LOG.error(e) + } + } + + private fun dropUnableToSaveProjectNotification(project: Project, readOnlyFiles: Array) { + val notifications = NotificationsManager.getNotificationsManager().getNotificationsOfType(javaClass(), project) + if (notifications.isEmpty()) { + Notifications.Bus.notify(UnableToSaveProjectNotification(project, readOnlyFiles), project) + } + else { + notifications[0].myFiles = readOnlyFiles + } + } + + private fun getFilesList(readonlyFiles: List>) = Array(readonlyFiles.size()) { readonlyFiles.get(it).second } + } +} + +class DefaultStorageChooser(private val scheme: StorageScheme) : StateStorageChooser> { + override fun selectStorages(storages: Array, component: PersistentStateComponent<*>, operation: StateStorageOperation): Array { + if (operation === StateStorageOperation.READ) { + val result = SmartList() + for (i in storages.indices.reversed()) { + val storage = storages[i] + if (storage.scheme == scheme) { + result.add(storage) + } + } + + for (storage in storages) { + if (storage.scheme == StorageScheme.DEFAULT && !result.contains(storage)) { + result.add(storage) + } + } + + return result.toTypedArray() + } + else if (operation == StateStorageOperation.WRITE) { + val result = SmartList() + for (storage in storages) { + if (storage.scheme == scheme) { + result.add(storage) + } + } + + if (result.isEmpty()) { + for (storage in storages) { + if (storage.scheme == StorageScheme.DEFAULT) { + result.add(storage) + } + } + } + + return result.toTypedArray() + } + else { + return emptyArray() + } + } +} \ No newline at end of file diff --git a/platform/configuration-store-impl/src/ProjectWithModulesStoreImpl.kt b/platform/configuration-store-impl/src/ProjectWithModulesStoreImpl.kt new file mode 100644 index 000000000000..e3cf9a33266d --- /dev/null +++ b/platform/configuration-store-impl/src/ProjectWithModulesStoreImpl.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2000-2015 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. + */ +package com.intellij.configurationStore + +import com.intellij.openapi.components.PathMacroManager +import com.intellij.openapi.components.StateStorage +import com.intellij.openapi.components.StateStorage.SaveSession +import com.intellij.openapi.components.TrackingPathMacroSubstitutor +import com.intellij.openapi.components.impl.stores.IComponentStore +import com.intellij.openapi.components.stateStore +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.project.impl.ProjectImpl +import com.intellij.openapi.project.impl.ProjectStoreClassProvider +import com.intellij.openapi.util.Pair +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.util.SmartList +import com.intellij.util.containers.ContainerUtil + +class PlatformLangProjectStoreClassProvider : ProjectStoreClassProvider { + override fun getProjectStoreClass(isDefaultProject: Boolean): Class { + return if (isDefaultProject) javaClass() else javaClass() + } +} + +class ProjectWithModulesStoreImpl(project: ProjectImpl, pathMacroManager: PathMacroManager) : ProjectStoreImpl(project, pathMacroManager) { + override fun reinitComponent(componentName: String, changedStorages: Set): Boolean { + if (super.reinitComponent(componentName, changedStorages)) { + return true + } + + for (module in getPersistentModules()) { + // we have to reinit all modules for component because we don't know affected module + module.stateStore.reinitComponent(componentName, changedStorages) + } + return true + } + + override fun getSubstitutors(): Array { + val result = SmartList() + ContainerUtil.addIfNotNull(result, getStateStorageManager().getMacroSubstitutor()) + + for (module in getPersistentModules()) { + ContainerUtil.addIfNotNull(result, module.stateStore.getStateStorageManager().getMacroSubstitutor()) + } + return result.toTypedArray() + } + + override fun isReloadPossible(componentNames: Set): Boolean { + if (!super.isReloadPossible(componentNames)) { + return false + } + + for (module in getPersistentModules()) { + if (!module.stateStore.isReloadPossible(componentNames)) { + return false + } + } + + return true + } + + private fun getPersistentModules() = ModuleManager.getInstance(myProject)?.getModules() ?: Module.EMPTY_ARRAY + + override protected fun beforeSave(readonlyFiles: List>) { + super.beforeSave(readonlyFiles) + + for (module in getPersistentModules()) { + module.stateStore.save(readonlyFiles) + } + } +} diff --git a/platform/configuration-store-impl/src/SchemeManagerImpl.kt b/platform/configuration-store-impl/src/SchemeManagerImpl.kt index 8a9559ad203d..596676415a90 100644 --- a/platform/configuration-store-impl/src/SchemeManagerImpl.kt +++ b/platform/configuration-store-impl/src/SchemeManagerImpl.kt @@ -26,7 +26,6 @@ import com.intellij.openapi.components.impl.stores.DirectoryStorageData import com.intellij.openapi.components.impl.stores.StorageUtil import com.intellij.openapi.components.impl.stores.StreamProvider import com.intellij.openapi.components.service -import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.extensions.AbstractExtensionPointBean import com.intellij.openapi.options.* import com.intellij.openapi.util.Comparing @@ -54,8 +53,6 @@ import java.io.InputStream import java.util.ArrayList import java.util.Collections -private val LOG = Logger.getInstance(javaClass>()) - public class SchemeManagerImpl(private val fileSpec: String, private val processor: SchemeProcessor, private val roamingType: RoamingType, diff --git a/platform/configuration-store-impl/src/StateStorageManagerImpl.kt b/platform/configuration-store-impl/src/StateStorageManagerImpl.kt new file mode 100644 index 000000000000..675f8c4572b0 --- /dev/null +++ b/platform/configuration-store-impl/src/StateStorageManagerImpl.kt @@ -0,0 +1,258 @@ +/* + * Copyright 2000-2015 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. + */ +package com.intellij.configurationStore + +import com.intellij.openapi.Disposable +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.components.* +import com.intellij.openapi.components.StateStorage.SaveSession +import com.intellij.openapi.components.StateStorageChooserEx.Resolution +import com.intellij.openapi.components.impl.stores.* +import com.intellij.openapi.util.Couple +import com.intellij.openapi.util.Disposer +import com.intellij.openapi.util.text.StringUtil +import com.intellij.util.PathUtilRt +import com.intellij.util.ReflectionUtil +import com.intellij.util.SmartList +import com.intellij.util.containers.ContainerUtil +import gnu.trove.THashMap +import org.jdom.Element +import org.picocontainer.MutablePicoContainer +import org.picocontainer.PicoContainer +import java.io.File +import java.util.LinkedHashMap +import java.util.UUID +import java.util.concurrent.locks.ReentrantLock +import java.util.regex.Pattern +import kotlin.concurrent.withLock +import kotlin.reflect.jvm.java + +abstract class StateStorageManagerImpl(private val pathMacroSubstitutor: TrackingPathMacroSubstitutor, protected val rootTagName: String, parentDisposable: Disposable, private val picoContainer: PicoContainer) : StateStorageManager, Disposable { + private val macros = LinkedHashMap() + private val storageLock = ReentrantLock() + private val storages = THashMap() + + private var streamProvider: StreamProvider? = null + + init { + Disposer.register(parentDisposable, this) + } + + companion object { + private val MACRO_PATTERN = Pattern.compile("(\\$[^\\$]*\\$)") + } + + override fun getStreamProvider() = streamProvider + + override fun setStreamProvider(value: StreamProvider?) { + streamProvider = value + } + + override fun getMacroSubstitutor() = pathMacroSubstitutor + + synchronized override fun addMacro(macro: String, expansion: String) { + assert(!macro.isEmpty()) + macros.put(macro, expansion) + } + + override fun getStateStorage(storageSpec: Storage): StateStorage { + @suppress("USELESS_CAST") + val storageClass = storageSpec.storageClass.java as Class + val key = if (storageClass == javaClass()) storageSpec.file else storageClass.getName() + + storageLock.withLock { + var stateStorage: StateStorage? = storages.get(key) + if (stateStorage == null) { + stateStorage = createStateStorage(storageClass, storageSpec.file, storageSpec.roamingType, storageSpec.stateSplitter.java) + storages.put(key, stateStorage) + } + return stateStorage + } + } + + override fun getStateStorage(fileSpec: String, roamingType: RoamingType): StateStorage? { + storageLock.withLock { + var stateStorage: StateStorage? = storages.get(fileSpec) + if (stateStorage == null) { + stateStorage = createStateStorage(javaClass(), fileSpec, roamingType, javaClass()) + storages.put(fileSpec, stateStorage) + } + return stateStorage + } + } + + override fun getCachedFileStateStorages(changed: Collection, deleted: Collection) = storageLock.withLock { Couple.of(getCachedFileStorages(changed), getCachedFileStorages(deleted)) } + + fun getCachedFileStorages(fileSpecs: Collection): Collection { + if (fileSpecs.isEmpty()) { + return emptyList() + } + + var result: MutableList? = null + for (fileSpec in fileSpecs) { + val storage = storages.get(fileSpec) + if (storage is FileBasedStorage) { + if (result == null) { + result = SmartList() + } + result.add(storage) + } + } + return result ?: emptyList() + } + + override fun getStorageFileNames() = storageLock.withLock { storages.keySet() } + + // overridden in upsource + protected fun createStateStorage(storageClass: Class, fileSpec: String, roamingType: RoamingType, SuppressWarnings("deprecation") stateSplitter: Class): StateStorage { + if (storageClass != javaClass()) { + val key = UUID.randomUUID().toString() + (picoContainer as MutablePicoContainer).registerComponentImplementation(key, storageClass) + return picoContainer.getComponentInstance(key) as StateStorage + } + + val filePath = expandMacros(fileSpec) + val file = File(filePath) + + //noinspection deprecation + if (stateSplitter != javaClass() && stateSplitter != javaClass()) { + return DirectoryBasedStorage(pathMacroSubstitutor, file, ReflectionUtil.newInstance(stateSplitter), this, createStorageTopicListener()) + } + + if (!ApplicationManager.getApplication().isHeadlessEnvironment() && PathUtilRt.getFileName(filePath).lastIndexOf('.') < 0) { + throw IllegalArgumentException("Extension is missing for storage file: " + filePath) + } + + val effectiveRoamingType = if (roamingType == RoamingType.PER_USER && fileSpec == StoragePathMacros.WORKSPACE_FILE) RoamingType.DISABLED else roamingType + beforeFileBasedStorageCreate() + return object : FileBasedStorage(file, fileSpec, effectiveRoamingType, getMacroSubstitutor(fileSpec), rootTagName, this@StateStorageManagerImpl, createStorageTopicListener(), streamProvider) { + override fun createStorageData() = this@StateStorageManagerImpl.createStorageData(myFileSpec, getFilePath()) + + override fun isUseXmlProlog() = this@StateStorageManagerImpl.isUseXmlProlog() + } + } + + override fun clearStateStorage(file: String) { + storageLock.withLock { storages.remove(file) } + } + + protected open fun createStorageTopicListener(): StateStorage.Listener? = null + + protected open fun isUseXmlProlog(): Boolean = true + + protected open fun beforeFileBasedStorageCreate() { + } + + protected open fun getMacroSubstitutor(fileSpec: String): TrackingPathMacroSubstitutor? = pathMacroSubstitutor + + protected abstract fun createStorageData(fileSpec: String, filePath: String): StorageData + + synchronized override fun expandMacros(file: String): String { + val matcher = MACRO_PATTERN.matcher(file) + while (matcher.find()) { + val m = matcher.group(1) + if (!macros.containsKey(m)) { + throw IllegalArgumentException("Unknown macro: " + m + " in storage file spec: " + file) + } + } + + var expanded = file + for (entry in macros.entrySet()) { + expanded = StringUtil.replace(expanded, entry.getKey(), entry.getValue()) + } + return expanded + } + + override fun collapseMacros(path: String): String { + var result = path + for (entry in macros.entrySet()) { + result = StringUtil.replace(result, entry.getValue(), entry.getKey()) + } + return result + } + + override fun startExternalization() = StateStorageManagerExternalizationSession(this) + + open class StateStorageManagerExternalizationSession(protected val storageManager: StateStorageManagerImpl) : StateStorageManager.ExternalizationSession { + private val mySessions = LinkedHashMap() + + override fun setState(storageSpecs: Array, component: Any, componentName: String, state: Any) { + val stateStorageChooser = if (component is StateStorageChooserEx) component else null + for (storageSpec in storageSpecs) { + val resolution = if (stateStorageChooser == null) Resolution.DO else stateStorageChooser.getResolution(storageSpec, StateStorageOperation.WRITE) + if (resolution === Resolution.SKIP) { + continue + } + + val stateStorage = storageManager.getStateStorage(storageSpec) + val session = getExternalizationSession(stateStorage) + session?.setState(component, componentName, if (storageSpec.deprecated || resolution === Resolution.CLEAR) Element("empty") else state, storageSpec) + } + } + + override fun setStateInOldStorage(component: Any, componentName: String, state: Any) { + val stateStorage = storageManager.getOldStorage(component, componentName, StateStorageOperation.WRITE) + if (stateStorage != null) { + val session = getExternalizationSession(stateStorage) + session?.setState(component, componentName, state, null) + } + } + + protected fun getExternalizationSession(stateStorage: StateStorage): StateStorage.ExternalizationSession? { + var session: StateStorage.ExternalizationSession? = mySessions.get(stateStorage) + if (session == null) { + session = stateStorage.startExternalization() + if (session != null) { + mySessions.put(stateStorage, session) + } + } + return session + } + + override fun createSaveSessions(): List { + if (mySessions.isEmpty()) { + return emptyList() + } + + var saveSessions: MutableList? = null + val externalizationSessions = mySessions.values() + for (session in externalizationSessions) { + val saveSession = session.createSaveSession() + if (saveSession != null) { + if (saveSessions == null) { + if (externalizationSessions.size() == 1) { + return listOf(saveSession) + } + saveSessions = SmartList() + } + saveSessions.add(saveSession) + } + } + return ContainerUtil.notNullize(saveSessions) + } + } + + override fun getOldStorage(component: Any, componentName: String, operation: StateStorageOperation): StateStorage? { + val oldStorageSpec = getOldStorageSpec(component, componentName, operation) + @suppress("DEPRECATED_SYMBOL_WITH_MESSAGE") + return if (oldStorageSpec == null) null else getStateStorage(oldStorageSpec, if (component is com.intellij.openapi.util.RoamingTypeDisabled) RoamingType.DISABLED else RoamingType.PER_USER) + } + + protected abstract fun getOldStorageSpec(component: Any, componentName: String, operation: StateStorageOperation): String? + + override fun dispose() { + } +} diff --git a/platform/configuration-store-impl/src/com/intellij/configurationStore/DefaultProjectStorage.java b/platform/configuration-store-impl/src/com/intellij/configurationStore/DefaultProjectStorage.java new file mode 100644 index 000000000000..4743ae71f38d --- /dev/null +++ b/platform/configuration-store-impl/src/com/intellij/configurationStore/DefaultProjectStorage.java @@ -0,0 +1,54 @@ +package com.intellij.configurationStore; + +import com.intellij.openapi.components.PathMacroManager; +import com.intellij.openapi.components.RoamingType; +import com.intellij.openapi.components.impl.stores.StorageData; +import com.intellij.openapi.components.impl.stores.XmlElementStorage; +import com.intellij.openapi.project.impl.ProjectManagerImpl; +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class DefaultProjectStorage extends XmlElementStorage { + private final DefaultProjectStoreImpl store; + private final ProjectManagerImpl projectManager; + + public DefaultProjectStorage(DefaultProjectStoreImpl store, PathMacroManager pathMacroManager, ProjectManagerImpl projectManager) { + super("", RoamingType.DISABLED, pathMacroManager.createTrackingSubstitutor(), "defaultProject", null); + + this.store = store; + this.projectManager = projectManager; + } + + @Override + @Nullable + protected Element loadLocalData() { + return store.getStateCopy(); + } + + @NotNull + @Override + protected XmlElementStorageSaveSession createSaveSession(@NotNull StorageData storageData) { + return new XmlElementStorageSaveSession(storageData) { + @Override + protected void doSave(@Nullable Element element) { + // we must set empty element instead of null as indicator - ProjectManager state is ready to save + projectManager.setDefaultProjectRootElement(element == null ? new Element("empty") : element); + } + + // we must not collapse paths here, because our solution is just a big hack + // by default, getElementToSave() returns collapsed paths -> setDefaultProjectRootElement -> project manager writeExternal -> save -> compare old and new - diff because old has expanded, but new collapsed + // -> needless save + @Override + protected boolean isCollapsePathsOnSave() { + return false; + } + }; + } + + @Override + @NotNull + protected StorageData createStorageData() { + return new StorageData(myRootElementName); + } +} diff --git a/platform/configuration-store-impl/src/com/intellij/configurationStore/DefaultStorageAnnotation.java b/platform/configuration-store-impl/src/com/intellij/configurationStore/DefaultStorageAnnotation.java new file mode 100644 index 000000000000..b9b89f475341 --- /dev/null +++ b/platform/configuration-store-impl/src/com/intellij/configurationStore/DefaultStorageAnnotation.java @@ -0,0 +1,55 @@ +package com.intellij.configurationStore; + +import com.intellij.openapi.components.*; +import org.jetbrains.annotations.NotNull; + +import java.lang.annotation.Annotation; + +@SuppressWarnings("ClassExplicitlyAnnotation") +public final class DefaultStorageAnnotation implements Storage { + @Override + public String id() { + return "___Default___"; + } + + @Override + public boolean isDefault() { + return true; + } + + @Override + public String file() { + return StoragePathMacros.PROJECT_FILE; + } + + @Override + public StorageScheme scheme() { + return StorageScheme.DEFAULT; + } + + @Override + public boolean deprecated() { + return true; + } + + @Override + public RoamingType roamingType() { + return RoamingType.PER_USER; + } + + @Override + public Class storageClass() { + return StateStorage.class; + } + + @Override + public Class stateSplitter() { + return StateSplitterEx.class; + } + + @NotNull + @Override + public Class annotationType() { + throw new UnsupportedOperationException("Method annotationType not implemented in " + getClass()); + } +} \ No newline at end of file diff --git a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/ApplicationPathMacroManager.java b/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/ApplicationPathMacroManager.java deleted file mode 100644 index 1a93f02aff2f..000000000000 --- a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/ApplicationPathMacroManager.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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. - */ -package com.intellij.openapi.components.impl; - -/** - * @author mike - */ -public class ApplicationPathMacroManager extends BasePathMacroManager { - public ApplicationPathMacroManager() { - super(null); - } -} diff --git a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ApplicationStoreImpl.java b/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ApplicationStoreImpl.java deleted file mode 100644 index 0c23e2e774c4..000000000000 --- a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ApplicationStoreImpl.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2000-2015 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. - */ -package com.intellij.openapi.components.impl.stores; - -import com.intellij.application.options.PathMacrosImpl; -import com.intellij.openapi.application.PathManager; -import com.intellij.openapi.application.impl.ApplicationImpl; -import com.intellij.openapi.components.*; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.NamedJDOMExternalizable; -import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VfsUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.messages.MessageBus; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -class ApplicationStoreImpl extends ComponentStoreImpl { - private static final Logger LOG = Logger.getInstance(ApplicationStoreImpl.class); - - private static final String DEFAULT_STORAGE_SPEC = StoragePathMacros.APP_CONFIG + "/" + PathManager.DEFAULT_OPTIONS_FILE_NAME + DirectoryStorageData.DEFAULT_EXT; - private static final String ROOT_ELEMENT_NAME = "application"; - - private final ApplicationImpl myApplication; - private final StateStorageManager myStateStorageManager; - - public ApplicationStoreImpl(@NotNull ApplicationImpl application, @NotNull PathMacroManager pathMacroManager) { - myApplication = application; - myStateStorageManager = new StateStorageManagerImpl(pathMacroManager.createTrackingSubstitutor(), ROOT_ELEMENT_NAME, application, application.getPicoContainer()) { - private boolean myConfigDirectoryRefreshed; - - @Nullable - protected StateStorage.Listener createStorageTopicListener() { - return myApplication.getMessageBus().syncPublisher(StateStorage.STORAGE_TOPIC); - } - - @NotNull - @Override - protected StorageData createStorageData(@NotNull String fileSpec, @NotNull String filePath) { - return new StorageData(ROOT_ELEMENT_NAME); - } - - @Nullable - @Override - protected String getOldStorageSpec(@NotNull Object component, @NotNull String componentName, @NotNull StateStorageOperation operation) { - if (component instanceof NamedJDOMExternalizable) { - return StoragePathMacros.APP_CONFIG + '/' + ((NamedJDOMExternalizable)component).getExternalFileName() + DirectoryStorageData.DEFAULT_EXT; - } - else { - return DEFAULT_STORAGE_SPEC; - } - } - - @Override - protected TrackingPathMacroSubstitutor getMacroSubstitutor(@NotNull String fileSpec) { - return fileSpec.equals(StoragePathMacros.APP_CONFIG + '/' + PathMacrosImpl.EXT_FILE_NAME + DirectoryStorageData.DEFAULT_EXT) ? null : super.getMacroSubstitutor(fileSpec); - } - - @Override - protected boolean isUseXmlProlog() { - return false; - } - - @Override - protected void beforeFileBasedStorageCreate() { - if (myConfigDirectoryRefreshed || (!myApplication.isUnitTestMode() && !myApplication.isDispatchThread())) { - return; - } - - try { - String configPath = getMacrosValue(StoragePathMacros.ROOT_CONFIG); - if (configPath == null) { - LOG.warn("Macros ROOT_CONFIG is not defined"); - return; - } - - VirtualFile configDir = LocalFileSystem.getInstance().refreshAndFindFileByPath(configPath); - if (configDir != null) { - VfsUtil.markDirtyAndRefresh(false, true, true, configDir); - } - } - finally { - myConfigDirectoryRefreshed = true; - } - } - }; - } - - @Override - @NotNull - protected MessageBus getMessageBus() { - return myApplication.getMessageBus(); - } - - @NotNull - @Override - public StateStorageManager getStateStorageManager() { - return myStateStorageManager; - } -} diff --git a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/BaseFileConfigurableStoreImpl.java b/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/BaseFileConfigurableStoreImpl.java deleted file mode 100644 index 26aa6c54eb4c..000000000000 --- a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/BaseFileConfigurableStoreImpl.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2000-2015 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. - */ -package com.intellij.openapi.components.impl.stores; - -import com.intellij.openapi.components.PathMacroManager; -import com.intellij.openapi.components.PathMacroSubstitutor; -import com.intellij.openapi.project.impl.ProjectManagerImpl; -import com.intellij.util.SmartList; -import org.jdom.Element; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -abstract class BaseFileConfigurableStoreImpl extends ComponentStoreImpl { - @NonNls protected static final String VERSION_OPTION = "version"; - @NonNls public static final String ATTRIBUTE_NAME = "name"; - - private static final List ourConversionProblemsStorage = new SmartList(); - - private StateStorageManager myStateStorageManager; - protected final PathMacroManager myPathMacroManager; - - protected BaseFileConfigurableStoreImpl(@NotNull PathMacroManager pathMacroManager) { - myPathMacroManager = pathMacroManager; - } - - protected static class BaseStorageData extends StorageData { - private int myVersion = ProjectManagerImpl.CURRENT_FORMAT_VERSION; - - public BaseStorageData(@NotNull String rootElementName) { - super(rootElementName); - } - - protected BaseStorageData(BaseStorageData storageData) { - super(storageData); - } - - @Override - public void load(@NotNull Element rootElement, @Nullable PathMacroSubstitutor pathMacroSubstitutor, boolean intern) { - super.load(rootElement, pathMacroSubstitutor, intern); - - String v = rootElement.getAttributeValue(VERSION_OPTION); - myVersion = v == null ? ProjectManagerImpl.CURRENT_FORMAT_VERSION : Integer.parseInt(v); - } - - @Override - @NotNull - protected final Element save(@NotNull Map newLiveStates) { - Element root = super.save(newLiveStates); - if (root == null) { - root = new Element(myRootElementName); - } - writeOptions(root, Integer.toString(myVersion)); - return root; - } - - protected void writeOptions(@NotNull Element root, @NotNull String versionString) { - root.setAttribute(VERSION_OPTION, versionString); - } - - @Override - public StorageData clone() { - return new BaseStorageData(this); - } - - @Nullable - @Override - public Set getChangedComponentNames(@NotNull StorageData newStorageData, @Nullable PathMacroSubstitutor substitutor) { - BaseStorageData data = (BaseStorageData)newStorageData; - if (myVersion != data.myVersion) { - return null; - } - return super.getChangedComponentNames(newStorageData, substitutor); - } - } - - @Nullable - static List getConversionProblemsStorage() { - return ourConversionProblemsStorage; - } - - @NotNull - @Override - protected final PathMacroManager getPathMacroManagerForDefaults() { - return myPathMacroManager; - } - - @NotNull - @Override - public final StateStorageManager getStateStorageManager() { - if (myStateStorageManager == null) { - myStateStorageManager = createStateStorageManager(); - } - return myStateStorageManager; - } - - @NotNull - protected abstract StateStorageManager createStateStorageManager(); -} diff --git a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java b/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java deleted file mode 100644 index 7a43c36265c9..000000000000 --- a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java +++ /dev/null @@ -1,529 +0,0 @@ -/* - * Copyright 2000-2015 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. - */ -package com.intellij.openapi.components.impl.stores; - -import com.intellij.openapi.application.*; -import com.intellij.openapi.application.ex.DecodeDefaultsUtil; -import com.intellij.openapi.components.*; -import com.intellij.openapi.components.StateStorage.SaveSession; -import com.intellij.openapi.components.StateStorageChooserEx.Resolution; -import com.intellij.openapi.components.impl.ComponentManagerImpl; -import com.intellij.openapi.components.impl.stores.StateStorageManager.ExternalizationSession; -import com.intellij.openapi.components.store.ReadOnlyModificationException; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.*; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess; -import com.intellij.util.ArrayUtilRt; -import com.intellij.util.ReflectionUtil; -import com.intellij.util.SmartList; -import com.intellij.util.containers.MultiMap; -import com.intellij.util.containers.SmartHashSet; -import com.intellij.util.lang.CompoundRuntimeException; -import com.intellij.util.messages.MessageBus; -import com.intellij.util.xmlb.JDOMXIncluder; -import gnu.trove.THashMap; -import org.jdom.Element; -import org.jdom.JDOMException; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.TestOnly; - -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.util.*; -import java.util.concurrent.CopyOnWriteArrayList; - -@SuppressWarnings({"deprecation"}) -public abstract class ComponentStoreImpl implements IComponentStore { - private static final Logger LOG = Logger.getInstance(ComponentStoreImpl.class); - private final Map myComponents = Collections.synchronizedMap(new THashMap()); - private final List mySettingsSavingComponents = new CopyOnWriteArrayList(); - - @Override - public void initComponent(@NotNull Object component, boolean service) { - if (component instanceof SettingsSavingComponent) { - mySettingsSavingComponents.add((SettingsSavingComponent)component); - } - - if (!(component instanceof JDOMExternalizable || component instanceof PersistentStateComponent)) { - return; - } - - AccessToken token = ReadAction.start(); - try { - String componentNameIfStateExists; - if (component instanceof PersistentStateComponent) { - componentNameIfStateExists = initPersistentComponent((PersistentStateComponent)component, null, false); - } - else { - componentNameIfStateExists = initJdomExternalizable((JDOMExternalizable)component); - } - - // if not service, so, component manager will check it later for all components - if (componentNameIfStateExists != null && service) { - Project project = getProject(); - Application app = ApplicationManager.getApplication(); - if (project != null && !app.isHeadlessEnvironment() && !app.isUnitTestMode() && project.isInitialized()) { - TrackingPathMacroSubstitutor substitutor = getStateStorageManager().getMacroSubstitutor(); - if (substitutor != null) { - StorageUtil.notifyUnknownMacros(substitutor, project, componentNameIfStateExists); - } - } - } - } - catch (StateStorageException e) { - throw e; - } - catch (ProcessCanceledException e) { - throw e; - } - catch (Exception e) { - LOG.error(e); - } - finally { - token.finish(); - } - } - - @Override - public final void save(@NotNull List> readonlyFiles) { - ExternalizationSession externalizationSession = myComponents.isEmpty() ? null : getStateStorageManager().startExternalization(); - if (externalizationSession != null) { - String[] names = ArrayUtilRt.toStringArray(myComponents.keySet()); - Arrays.sort(names); - for (String name : names) { - commitComponent(externalizationSession, myComponents.get(name), name); - } - } - - List errors = null; - for (SettingsSavingComponent settingsSavingComponent : mySettingsSavingComponents) { - try { - settingsSavingComponent.save(); - } - catch (Throwable e) { - if (errors == null) { - errors = new SmartList(); - } - errors.add(e); - } - } - - errors = doSave(externalizationSession == null ? null : externalizationSession.createSaveSessions(), readonlyFiles, errors); - CompoundRuntimeException.doThrow(errors); - } - - @TestOnly - @Override - public void saveApplicationComponent(@NotNull Object component) { - StateStorageManager.ExternalizationSession externalizationSession = getStateStorageManager().startExternalization(); - if (externalizationSession == null) { - return; - } - - commitComponent(externalizationSession, component, null); - List sessions = externalizationSession.createSaveSessions(); - if (sessions.isEmpty()) { - return; - } - - final File file; - State state = StoreUtil.getStateSpec(component.getClass()); - if (state != null) { - file = new File(getStateStorageManager().expandMacros(findNonDeprecated(state.storages()).file())); - } - else if (component instanceof ExportableApplicationComponent && component instanceof NamedJDOMExternalizable) { - file = PathManager.getOptionsFile((NamedJDOMExternalizable)component); - } - else { - throw new AssertionError(component.getClass() + " doesn't have @State annotation and doesn't implement ExportableApplicationComponent"); - } - - AccessToken token = WriteAction.start(); - try { - VfsRootAccess.allowRootAccess(file.getAbsolutePath()); - CompoundRuntimeException.doThrow(doSave(sessions, Collections.>emptyList(), null)); - } - finally { - try { - VfsRootAccess.disallowRootAccess(file.getAbsolutePath()); - } - finally { - token.finish(); - } - } - } - - private static Storage findNonDeprecated(Storage[] storages) { - for (Storage storage : storages) { - if (!storage.deprecated()) { - return storage; - } - } - throw new AssertionError("All storages are deprecated"); - } - - private void commitComponent(@NotNull ExternalizationSession externalizationSession, @NotNull Object component, @Nullable String componentName) { - if (component instanceof PersistentStateComponent) { - commitPersistentComponent((PersistentStateComponent)component, externalizationSession, componentName); - } - else if (component instanceof JDOMExternalizable) { - externalizationSession.setStateInOldStorage(component, componentName == null ? ComponentManagerImpl.getComponentName(component) : componentName, component); - } - } - - @Nullable - protected List doSave(@Nullable List saveSessions, @NotNull List> readonlyFiles, @Nullable List errors) { - if (saveSessions != null) { - for (SaveSession session : saveSessions) { - errors = executeSave(session, readonlyFiles, errors); - } - } - return errors; - } - - @Nullable - protected static List executeSave(@NotNull SaveSession session, @NotNull List> readonlyFiles, @Nullable List errors) { - try { - session.save(); - } - catch (ReadOnlyModificationException e) { - LOG.warn(e); - readonlyFiles.add(Pair.create(e.getSession() == null ? session : e.getSession(), e.getFile())); - } - catch (Exception e) { - if (errors == null) { - errors = new SmartList(); - } - errors.add(e); - } - return errors; - } - - private void commitPersistentComponent(@NotNull PersistentStateComponent component, @NotNull ExternalizationSession session, @Nullable String componentName) { - T state = component.getState(); - if (state != null) { - Storage[] storageSpecs = getComponentStorageSpecs(component, StoreUtil.getStateSpec(component), StateStorageOperation.WRITE); - session.setState(storageSpecs, component, componentName == null ? StoreUtil.getComponentName(component) : componentName, state); - } - } - - @Nullable - private String initJdomExternalizable(@NotNull JDOMExternalizable component) { - String componentName = ComponentManagerImpl.getComponentName(component); - doAddComponent(componentName, component); - - if (optimizeTestLoading()) { - return null; - } - - loadJdomDefaults(component, componentName); - - StateStorage stateStorage = getStateStorageManager().getOldStorage(component, componentName, StateStorageOperation.READ); - if (stateStorage == null) { - return null; - } - - Element element = stateStorage.getState(component, componentName, Element.class, null); - if (element == null) { - return null; - } - - try { - if (LOG.isDebugEnabled()) { - LOG.debug("Loading configuration for " + component.getClass()); - } - component.readExternal(element); - } - catch (InvalidDataException e) { - LOG.error(e); - return null; - } - - return componentName; - } - - private void doAddComponent(String componentName, Object component) { - Object existing = myComponents.get(componentName); - if (existing != null && existing != component) { - LOG.error("Conflicting component name '" + componentName + "': " + existing.getClass() + " and " + component.getClass()); - } - myComponents.put(componentName, component); - } - - private void loadJdomDefaults(@NotNull JDOMExternalizable component, @NotNull String componentName) { - try { - Element defaultState = getDefaultState(component, componentName, Element.class); - if (defaultState != null) { - component.readExternal(defaultState); - } - } - catch (Exception e) { - LOG.error("Cannot load defaults for " + component.getClass(), e); - } - } - - @Nullable - protected Project getProject() { - return null; - } - - @Nullable - private String initPersistentComponent(@NotNull PersistentStateComponent component, @Nullable Set changedStorages, boolean reloadData) { - State stateSpec = StoreUtil.getStateSpec(component); - String name = stateSpec.name(); - if (changedStorages == null || !reloadData) { - doAddComponent(name, component); - } - if (optimizeTestLoading()) { - return null; - } - - Class stateClass = ComponentSerializationUtil.getStateClass(component.getClass()); - if (!stateSpec.defaultStateAsResource() && LOG.isDebugEnabled() && getDefaultState(component, name, stateClass) != null) { - LOG.error(name + " has default state, but not marked to load it"); - } - - T state = stateSpec.defaultStateAsResource() ? getDefaultState(component, name, stateClass) : null; - Storage[] storageSpecs = getComponentStorageSpecs(component, stateSpec, StateStorageOperation.READ); - StateStorageChooserEx stateStorageChooser = component instanceof StateStorageChooserEx ? (StateStorageChooserEx)component : null; - for (Storage storageSpec : storageSpecs) { - Resolution resolution = stateStorageChooser == null ? Resolution.DO : stateStorageChooser.getResolution(storageSpec, StateStorageOperation.READ); - if (resolution == Resolution.SKIP) { - continue; - } - - StateStorage stateStorage = getStateStorageManager().getStateStorage(storageSpec); - boolean forcedState = false; - if (stateStorage != null && (stateStorage.hasState(component, name, stateClass, reloadData) || - (forcedState = changedStorages != null && changedStorages.contains(stateStorage)))) { - state = stateStorage.getState(component, name, stateClass, state); - if (state == null && forcedState) { - // state will be null if file deleted - // we must create empty (initial) state to reinit component - state = DefaultStateSerializer.deserializeState(new Element("state"), stateClass, null); - } - break; - } - } - - if (state != null) { - component.loadState(state); - } - - return name; - } - - @Nullable - protected PathMacroManager getPathMacroManagerForDefaults() { - return null; - } - - @Nullable - protected T getDefaultState(@NotNull Object component, @NotNull String componentName, @NotNull final Class stateClass) { - URL url = DecodeDefaultsUtil.getDefaults(component, componentName); - if (url == null) { - return null; - } - - try { - Element documentElement = JDOMXIncluder.resolve(JDOMUtil.loadDocument(url), url.toExternalForm()).detachRootElement(); - - PathMacroManager pathMacroManager = getPathMacroManagerForDefaults(); - if (pathMacroManager != null) { - pathMacroManager.expandPaths(documentElement); - } - - return DefaultStateSerializer.deserializeState(documentElement, stateClass, null); - } - catch (IOException e) { - throw new StateStorageException("Error loading state from " + url, e); - } - catch (JDOMException e) { - throw new StateStorageException("Error loading state from " + url, e); - } - } - - @NotNull - protected Storage[] getComponentStorageSpecs(@NotNull PersistentStateComponent component, - @NotNull State stateSpec, - @NotNull StateStorageOperation operation) { - Storage[] storages = stateSpec.storages(); - if (storages.length == 1) { - return storages; - } - assert storages.length > 0; - - StateStorageChooser> storageChooser; - Class storageChooserClass = stateSpec.storageChooser(); - if (storageChooserClass != StateStorageChooser.class) { - //noinspection unchecked - storageChooser = ReflectionUtil.newInstance(storageChooserClass); - return storageChooser.selectStorages(storages, component, operation); - } - - StateStorageChooser> defaultStateStorageChooser = getDefaultStateStorageChooser(); - if (defaultStateStorageChooser != null) { - return defaultStateStorageChooser.selectStorages(storages, component, operation); - } - - if (component instanceof StateStorageChooserEx) { - return storages; - } - - int actualStorageCount = 0; - for (Storage storage : storages) { - if (!storage.deprecated()) { - actualStorageCount++; - } - } - - if (actualStorageCount > 1) { - LOG.error("State chooser not specified for: " + component.getClass()); - } - - if (!storages[0].deprecated()) { - boolean othersAreDeprecated = true; - for (int i = 1; i < storages.length; i++) { - if (!storages[i].deprecated()) { - othersAreDeprecated = false; - break; - } - } - - if (othersAreDeprecated) { - return storages; - } - } - - Storage[] sorted = Arrays.copyOf(storages, storages.length); - Arrays.sort(sorted, new Comparator() { - @Override - public int compare(Storage o1, Storage o2) { - int w1 = o1.deprecated() ? 1 : 0; - int w2 = o2.deprecated() ? 1 : 0; - return w1 - w2; - } - }); - return sorted; - } - - protected boolean optimizeTestLoading() { - return false; - } - - @Nullable - protected StateStorageChooser> getDefaultStateStorageChooser() { - return null; - } - - @Override - public boolean isReloadPossible(@NotNull final Set componentNames) { - for (String componentName : componentNames) { - final Object component = myComponents.get(componentName); - if (component != null && (!(component instanceof PersistentStateComponent) || !StoreUtil.getStateSpec((PersistentStateComponent)component).reloadable())) { - return false; - } - } - - return true; - } - - @Override - @NotNull - public final Collection getNotReloadableComponents(@NotNull Collection componentNames) { - Set notReloadableComponents = null; - for (String componentName : componentNames) { - Object component = myComponents.get(componentName); - if (component != null && (!(component instanceof PersistentStateComponent) || !StoreUtil.getStateSpec((PersistentStateComponent)component).reloadable())) { - if (notReloadableComponents == null) { - notReloadableComponents = new LinkedHashSet(); - } - notReloadableComponents.add(componentName); - } - } - return notReloadableComponents == null ? Collections.emptySet() : notReloadableComponents; - } - - @Override - public void reinitComponents(@NotNull Set componentNames, boolean reloadData) { - reinitComponents(componentNames, Collections.emptySet(), Collections.emptySet()); - } - - @Override - public boolean reinitComponent(@NotNull String componentName, @NotNull Set changedStorages) { - PersistentStateComponent component = (PersistentStateComponent)myComponents.get(componentName); - if (component == null) { - return false; - } - else { - boolean changedStoragesEmpty = changedStorages.isEmpty(); - initPersistentComponent(component, changedStoragesEmpty ? null : changedStorages, changedStoragesEmpty); - return true; - } - } - - @NotNull - protected abstract MessageBus getMessageBus(); - - @Override - @Nullable - public final Collection reload(@NotNull MultiMap changedStorages) { - if (changedStorages.isEmpty()) { - return Collections.emptySet(); - } - - Set componentNames = new SmartHashSet(); - for (StateStorage storage : changedStorages.keySet()) { - try { - // we must update (reload in-memory storage data) even if non-reloadable component will be detected later - // not saved -> user does own modification -> new (on disk) state will be overwritten and not applied - storage.analyzeExternalChangesAndUpdateIfNeed(changedStorages.get(storage), componentNames); - } - catch (Throwable e) { - LOG.error(e); - } - } - - if (componentNames.isEmpty()) { - return Collections.emptySet(); - } - - Collection notReloadableComponents = getNotReloadableComponents(componentNames); - reinitComponents(componentNames, notReloadableComponents, changedStorages.keySet()); - return notReloadableComponents.isEmpty() ? null : notReloadableComponents; - } - - // used in settings repository plugin - public void reinitComponents(@NotNull Set componentNames, @NotNull Collection notReloadableComponents, @NotNull Set changedStorages) { - MessageBus messageBus = getMessageBus(); - messageBus.syncPublisher(BatchUpdateListener.TOPIC).onBatchUpdateStarted(); - try { - for (String componentName : componentNames) { - if (!notReloadableComponents.contains(componentName)) { - reinitComponent(componentName, changedStorages); - } - } - } - finally { - messageBus.syncPublisher(BatchUpdateListener.TOPIC).onBatchUpdateFinished(); - } - } -} diff --git a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/DefaultProjectStoreImpl.java b/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/DefaultProjectStoreImpl.java deleted file mode 100644 index a9e3170d0071..000000000000 --- a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/DefaultProjectStoreImpl.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright 2000-2015 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. - */ -package com.intellij.openapi.components.impl.stores; - -import com.intellij.openapi.components.*; -import com.intellij.openapi.components.StateStorage.SaveSession; -import com.intellij.openapi.project.impl.ProjectImpl; -import com.intellij.openapi.project.impl.ProjectManagerImpl; -import com.intellij.openapi.util.Couple; -import com.intellij.util.containers.ContainerUtil; -import org.jdom.Element; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -public class DefaultProjectStoreImpl extends ProjectStoreImpl { - private final ProjectManagerImpl myProjectManager; - @NonNls private static final String ROOT_TAG_NAME = "defaultProject"; - - public DefaultProjectStoreImpl(@NotNull ProjectImpl project, @NotNull ProjectManagerImpl projectManager, @NotNull PathMacroManager pathMacroManager) { - super(project, pathMacroManager); - - myProjectManager = projectManager; - } - - @Nullable - Element getStateCopy() { - final Element element = myProjectManager.getDefaultProjectRootElement(); - return element != null ? element.clone() : null; - } - - @NotNull - @Override - protected StateStorageManager createStateStorageManager() { - final XmlElementStorage storage = new XmlElementStorage("", RoamingType.DISABLED, myPathMacroManager.createTrackingSubstitutor(), - ROOT_TAG_NAME, null) { - @Override - @Nullable - protected Element loadLocalData() { - return getStateCopy(); - } - - @NotNull - @Override - protected XmlElementStorageSaveSession createSaveSession(@NotNull StorageData storageData) { - return new XmlElementStorageSaveSession(storageData) { - @Override - protected void doSave(@Nullable Element element) { - // we must set empty element instead of null as indicator - ProjectManager state is ready to save - myProjectManager.setDefaultProjectRootElement(element == null ? new Element("empty") : element); - } - - // we must not collapse paths here, because our solution is just a big hack - // by default, getElementToSave() returns collapsed paths -> setDefaultProjectRootElement -> project manager writeExternal -> save -> compare old and new - diff because old has expanded, but new collapsed - // -> needless save - @Override - protected boolean isCollapsePathsOnSave() { - return false; - } - }; - } - - @Override - @NotNull - protected StorageData createStorageData() { - return new BaseStorageData(ROOT_TAG_NAME); - } - }; - - //noinspection deprecation - return new StateStorageManager() { - @Override - public void addMacro(@NotNull String macro, @NotNull String expansion) { - throw new UnsupportedOperationException("Method addMacro not implemented in " + getClass()); - } - - @Override - @Nullable - public TrackingPathMacroSubstitutor getMacroSubstitutor() { - return null; - } - - @Override - @Nullable - public StateStorage getStateStorage(@NotNull Storage storageSpec) { - return storage; - } - - @Nullable - @Override - public StateStorage getStateStorage(@NotNull String fileSpec, @NotNull RoamingType roamingType) { - return storage; - } - - @NotNull - @Override - public Couple> getCachedFileStateStorages(@NotNull Collection changed, @NotNull Collection deleted) { - return new Couple>(Collections.emptyList(), Collections.emptyList()); - } - - @Override - public void clearStateStorage(@NotNull String file) { - } - - @Nullable - @Override - public ExternalizationSession startExternalization() { - StateStorage.ExternalizationSession externalizationSession = storage.startExternalization(); - return externalizationSession == null ? null : new MyExternalizationSession(externalizationSession); - } - - @NotNull - @Override - public String expandMacros(@NotNull String file) { - throw new UnsupportedOperationException("Method expandMacros not implemented in " + getClass()); - } - - @NotNull - @Override - public String collapseMacros(@NotNull String path) { - throw new UnsupportedOperationException("Method collapseMacros not implemented in " + getClass()); - } - - @Override - @Nullable - public StateStorage getOldStorage(@NotNull Object component, @NotNull String componentName, @NotNull StateStorageOperation operation) { - return storage; - } - - @Override - public void setStreamProvider(@Nullable StreamProvider streamProvider) { - throw new UnsupportedOperationException("Method setStreamProvider not implemented in " + getClass()); - } - - @Nullable - @Override - public StreamProvider getStreamProvider() { - throw new UnsupportedOperationException("Method getStreamProviders not implemented in " + getClass()); - } - - @NotNull - @Override - public Collection getStorageFileNames() { - throw new UnsupportedOperationException("Method getStorageFileNames not implemented in " + getClass()); - } - }; - } - - private static class MyExternalizationSession implements StateStorageManager.ExternalizationSession { - @NotNull final StateStorage.ExternalizationSession externalizationSession; - - public MyExternalizationSession(@NotNull StateStorage.ExternalizationSession externalizationSession) { - this.externalizationSession = externalizationSession; - } - - @Override - public void setState(@NotNull Storage[] storageSpecs, @NotNull Object component, @NotNull String componentName, @NotNull Object state) { - externalizationSession.setState(component, componentName, state, null); - } - - @Override - public void setStateInOldStorage(@NotNull Object component, @NotNull String componentName, @NotNull Object state) { - externalizationSession.setState(component, componentName, state, null); - } - - @NotNull - @Override - public List createSaveSessions() { - return ContainerUtil.createMaybeSingletonList(externalizationSession.createSaveSession()); - } - } -} diff --git a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ModuleFileData.java b/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ModuleFileData.java deleted file mode 100644 index 76a997237e37..000000000000 --- a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ModuleFileData.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2000-2015 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. - */ -package com.intellij.openapi.components.impl.stores; - -import com.intellij.openapi.components.PathMacroSubstitutor; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.OptionManager; -import com.intellij.openapi.util.text.StringUtil; -import org.jdom.Attribute; -import org.jdom.Element; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Set; -import java.util.TreeMap; - -final class ModuleFileData extends BaseFileConfigurableStoreImpl.BaseStorageData implements OptionManager { - private TreeMap options; - private final Module myModule; - - private boolean dirty = true; - - public ModuleFileData(@NotNull String rootElementName, @NotNull Module module) { - super(rootElementName); - - myModule = module; - options = new TreeMap(); - } - - @Override - public boolean isDirty() { - return dirty; - } - - private ModuleFileData(@NotNull ModuleFileData storageData) { - super(storageData); - - myModule = storageData.myModule; - dirty = storageData.dirty; - options = new TreeMap(storageData.options); - } - - @Override - public void load(@NotNull Element rootElement, @Nullable PathMacroSubstitutor pathMacroSubstitutor, boolean intern) { - super.load(rootElement, pathMacroSubstitutor, intern); - - for (Attribute attribute : rootElement.getAttributes()) { - String name = attribute.getName(); - if (!name.equals(BaseFileConfigurableStoreImpl.VERSION_OPTION) && !StringUtil.isEmpty(name)) { - options.put(name, attribute.getValue()); - } - } - - dirty = false; - } - - @Override - protected void writeOptions(@NotNull Element root, @NotNull String versionString) { - if (!options.isEmpty()) { - for (String key : options.keySet()) { - String value = options.get(key); - if (value != null) { - root.setAttribute(key, value); - } - } - } - // need be last for compat reasons - super.writeOptions(root, versionString); - - dirty = false; - } - - @Override - public StorageData clone() { - return new ModuleFileData(this); - } - - @Nullable - @Override - public Set getChangedComponentNames(@NotNull StorageData newStorageData, @Nullable PathMacroSubstitutor substitutor) { - final ModuleFileData data = (ModuleFileData)newStorageData; - if (!options.equals(data.options)) { - return null; - } - - return super.getChangedComponentNames(newStorageData, substitutor); - } - - @Override - public void setOption(@NotNull String key, @NotNull String value) { - if (!value.equals(options.put(key, value))) { - dirty = true; - } - } - - @Override - public void clearOption(@NotNull String key) { - if (options.remove(key) != null) { - dirty = true; - } - } - - @Override - @Nullable - public String getOptionValue(@NotNull String key) { - return options.get(key); - } -} diff --git a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ModuleStateStorageManager.java b/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ModuleStateStorageManager.java deleted file mode 100644 index ced6c3b206cd..000000000000 --- a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ModuleStateStorageManager.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2000-2015 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. - */ -package com.intellij.openapi.components.impl.stores; - -import com.intellij.openapi.components.*; -import com.intellij.openapi.module.Module; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collections; -import java.util.List; - -public class ModuleStateStorageManager extends StateStorageManagerImpl { - @NonNls private static final String ROOT_TAG_NAME = "module"; - private final Module myModule; - - public ModuleStateStorageManager(@NotNull TrackingPathMacroSubstitutor pathMacroManager, @NotNull Module module) { - super(pathMacroManager, ROOT_TAG_NAME, module, module.getPicoContainer()); - - myModule = module; - } - - @NotNull - @Override - protected StorageData createStorageData(@NotNull String fileSpec, @NotNull String filePath) { - return new ModuleFileData(ROOT_TAG_NAME, myModule); - } - - @NotNull - @Override - public ExternalizationSession startExternalization() { - return new StateStorageManagerExternalizationSession() { - @NotNull - @Override - public List createSaveSessions() { - StateStorageManagerImpl storageManager = (StateStorageManagerImpl)ComponentsPackage.getStateStore(myModule).getStateStorageManager(); - FileBasedStorage storage = ContainerUtil.getFirstItem(storageManager.getCachedFileStorages(Collections.singletonList(StoragePathMacros.MODULE_FILE))); - if (storage != null && storage.getStorageData().isDirty()) { - // force XmlElementStorageSaveSession creation - getExternalizationSession(storage); - } - return super.createSaveSessions(); - } - }; - } - - @Nullable - @Override - protected String getOldStorageSpec(@NotNull Object component, @NotNull String componentName, @NotNull StateStorageOperation operation) { - return StoragePathMacros.MODULE_FILE; - } - - @NotNull - @Override - protected StateStorage.Listener createStorageTopicListener() { - return myModule.getProject().getMessageBus().syncPublisher(StateStorage.PROJECT_STORAGE_TOPIC); - } -} \ No newline at end of file diff --git a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java b/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java deleted file mode 100644 index 62429b486ad0..000000000000 --- a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2000-2015 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. - */ -package com.intellij.openapi.components.impl.stores; - -import com.intellij.openapi.components.PathMacroManager; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ex.ProjectEx; -import com.intellij.util.messages.MessageBus; -import org.jetbrains.annotations.NotNull; - -final class ModuleStoreImpl extends BaseFileConfigurableStoreImpl { - private final Module myModule; - - public ModuleStoreImpl(@NotNull Module module, @NotNull PathMacroManager pathMacroManager) { - super(pathMacroManager); - - myModule = module; - } - - @Override - protected Project getProject() { - return myModule.getProject(); - } - - @Override - protected boolean optimizeTestLoading() { - return ((ProjectEx)myModule.getProject()).isOptimiseTestLoadSpeed(); - } - - @NotNull - @Override - protected MessageBus getMessageBus() { - return myModule.getMessageBus(); - } - - @NotNull - @Override - protected StateStorageManager createStateStorageManager() { - return new ModuleStateStorageManager(myPathMacroManager.createTrackingSubstitutor(), myModule); - } -} diff --git a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/PlatformLangProjectStoreClassProvider.java b/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/PlatformLangProjectStoreClassProvider.java deleted file mode 100644 index 5655f526dba8..000000000000 --- a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/PlatformLangProjectStoreClassProvider.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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. - */ - -package com.intellij.openapi.components.impl.stores; - -import com.intellij.openapi.project.impl.ProjectStoreClassProvider; -import org.jetbrains.annotations.NotNull; - -/** - * @author yole - */ -class PlatformLangProjectStoreClassProvider implements ProjectStoreClassProvider { - @NotNull - @Override - public Class getProjectStoreClass(final boolean isDefaultProject) { - return isDefaultProject ? DefaultProjectStoreImpl.class : ProjectWithModulesStoreImpl.class; - } -} diff --git a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ProjectStateStorageManager.java b/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ProjectStateStorageManager.java deleted file mode 100644 index 6a4c4d047d57..000000000000 --- a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ProjectStateStorageManager.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2000-2015 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. - */ -package com.intellij.openapi.components.impl.stores; - -import com.intellij.openapi.components.*; -import com.intellij.openapi.project.impl.ProjectImpl; -import org.jdom.Element; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class ProjectStateStorageManager extends StateStorageManagerImpl { - protected final ProjectImpl myProject; - @NonNls protected static final String ROOT_TAG_NAME = "project"; - - public ProjectStateStorageManager(@NotNull TrackingPathMacroSubstitutor macroSubstitutor, @NotNull ProjectImpl project) { - super(macroSubstitutor, ROOT_TAG_NAME, project, project.getPicoContainer()); - myProject = project; - } - - @NotNull - @Override - protected StorageData createStorageData(@NotNull String fileSpec, @NotNull String filePath) { - if (fileSpec.equals(StoragePathMacros.PROJECT_FILE)) { - return createIprStorageData(filePath); - } - if (fileSpec.equals(StoragePathMacros.WORKSPACE_FILE)) { - return new ProjectStoreImpl.WsStorageData(ROOT_TAG_NAME, myProject); - } - return new ProjectStoreImpl.ProjectStorageData(ROOT_TAG_NAME, myProject); - } - - @NotNull - protected StorageData createIprStorageData(@NotNull String filePath) { - return new ProjectStoreImpl.IprStorageData(ROOT_TAG_NAME, myProject); - } - - @Nullable - @Override - protected String getOldStorageSpec(@NotNull Object component, @NotNull String componentName, @NotNull StateStorageOperation operation) { - boolean workspace = myProject.isWorkspaceComponent(component.getClass()); - String fileSpec = workspace ? StoragePathMacros.WORKSPACE_FILE : StoragePathMacros.PROJECT_FILE; - StateStorage storage = getStateStorage(fileSpec, workspace ? RoamingType.DISABLED : RoamingType.PER_USER); - if (operation == StateStorageOperation.READ && storage != null && workspace && !storage.hasState(component, componentName, Element.class, false)) { - fileSpec = StoragePathMacros.PROJECT_FILE; - } - return fileSpec; - } - - @NotNull - @Override - protected StateStorage.Listener createStorageTopicListener() { - return myProject.getMessageBus().syncPublisher(StateStorage.PROJECT_STORAGE_TOPIC); - } -} diff --git a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ProjectStoreImpl.java b/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ProjectStoreImpl.java deleted file mode 100644 index b8638ab5059f..000000000000 --- a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ProjectStoreImpl.java +++ /dev/null @@ -1,661 +0,0 @@ -/* - * Copyright 2000-2015 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. - */ -package com.intellij.openapi.components.impl.stores; - -import com.intellij.CommonBundle; -import com.intellij.ide.highlighter.ProjectFileType; -import com.intellij.ide.highlighter.WorkspaceFileType; -import com.intellij.notification.Notifications; -import com.intellij.notification.NotificationsManager; -import com.intellij.openapi.application.*; -import com.intellij.openapi.components.*; -import com.intellij.openapi.components.StateStorage.SaveSession; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.fileTypes.FileTypeManager; -import com.intellij.openapi.help.HelpManager; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectBundle; -import com.intellij.openapi.project.impl.ProjectImpl; -import com.intellij.openapi.project.impl.ProjectManagerImpl; -import com.intellij.openapi.project.impl.ProjectManagerImpl.UnableToSaveProjectNotification; -import com.intellij.openapi.ui.MessageDialogBuilder; -import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.io.FileUtilRt; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.*; -import com.intellij.util.PathUtilRt; -import com.intellij.util.SmartList; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.lang.CompoundRuntimeException; -import com.intellij.util.messages.MessageBus; -import org.jdom.Element; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.*; -import java.lang.annotation.Annotation; -import java.util.ArrayList; -import java.util.List; - -public class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProjectStore { - private static final Logger LOG = Logger.getInstance(ProjectStoreImpl.class); - - private static final Storage DEFAULT_STORAGE_ANNOTATION = new MyStorage(); - - @NonNls private static final String OLD_PROJECT_SUFFIX = "_old."; - - private static int originalVersion = -1; - - protected ProjectImpl myProject; - @NotNull - private StorageScheme myScheme = StorageScheme.DEFAULT; - private String myPresentableUrl; - - public ProjectStoreImpl(@NotNull ProjectImpl project, @NotNull PathMacroManager pathMacroManager) { - super(pathMacroManager); - - myProject = project; - } - - @SuppressWarnings("unused") //used in upsource - protected void setStorageScheme(@NotNull StorageScheme scheme) { - myScheme = scheme; - } - - @Override - public boolean checkVersion() { - if (originalVersion >= 0 && originalVersion < ProjectManagerImpl.CURRENT_FORMAT_VERSION) { - final VirtualFile projectFile = getProjectFile(); - LOG.assertTrue(projectFile != null); - String message = ProjectBundle.message("project.convert.old.prompt", projectFile.getName(), - ApplicationNamesInfo.getInstance().getProductName(), - projectFile.getNameWithoutExtension() + OLD_PROJECT_SUFFIX + projectFile.getExtension()); - if (Messages.showYesNoDialog(message, CommonBundle.getWarningTitle(), Messages.getWarningIcon()) != Messages.YES) return false; - - List conversionProblems = getConversionProblemsStorage(); - if (!ContainerUtil.isEmpty(conversionProblems)) { - StringBuilder buffer = new StringBuilder(); - buffer.append(ProjectBundle.message("project.convert.problems.detected")); - for (String s : conversionProblems) { - buffer.append('\n'); - buffer.append(s); - } - buffer.append(ProjectBundle.message("project.convert.problems.help")); - if (Messages.showOkCancelDialog(myProject, buffer.toString(), ProjectBundle.message("project.convert.problems.title"), - ProjectBundle.message("project.convert.problems.help.button"), - CommonBundle.getCloseButtonText(), Messages.getWarningIcon()) == Messages.OK) { - HelpManager.getInstance().invokeHelp("project.migrationProblems"); - } - } - - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - try { - VirtualFile projectDir = projectFile.getParent(); - assert projectDir != null; - - backup(projectDir, projectFile); - - VirtualFile workspaceFile = getWorkspaceFile(); - if (workspaceFile != null) { - backup(projectDir, workspaceFile); - } - } - catch (IOException e) { - LOG.error(e); - } - } - - private void backup(final VirtualFile projectDir, final VirtualFile vile) throws IOException { - final String oldName = vile.getNameWithoutExtension() + OLD_PROJECT_SUFFIX + vile.getExtension(); - VfsUtil.saveText(projectDir.findOrCreateChildData(this, oldName), VfsUtilCore.loadText(vile)); - } - }); - } - - return originalVersion <= ProjectManagerImpl.CURRENT_FORMAT_VERSION || - MessageDialogBuilder.yesNo(CommonBundle.getWarningTitle(), - ProjectBundle.message("project.load.new.version.warning", myProject.getName(), ApplicationNamesInfo.getInstance().getProductName())) - .icon(Messages.getWarningIcon()) - .project(myProject).is(); - } - - @NotNull - @Override - public TrackingPathMacroSubstitutor[] getSubstitutors() { - return new TrackingPathMacroSubstitutor[] {getStateStorageManager().getMacroSubstitutor()}; - } - - @Override - protected boolean optimizeTestLoading() { - return myProject.isOptimiseTestLoadSpeed(); - } - - @Override - protected Project getProject() { - return myProject; - } - - @Override - public void setProjectFilePath(@NotNull final String filePath) { - final StateStorageManager stateStorageManager = getStateStorageManager(); - final LocalFileSystem fs = LocalFileSystem.getInstance(); - - final File file = new File(filePath); - if (isIprPath(file)) { - myScheme = StorageScheme.DEFAULT; - - stateStorageManager.addMacro(StoragePathMacros.PROJECT_FILE, filePath); - - final String workspacePath = composeWsPath(filePath); - stateStorageManager.addMacro(StoragePathMacros.WORKSPACE_FILE, workspacePath); - - ApplicationManager.getApplication().invokeAndWait(new Runnable() { - @Override - public void run() { - VfsUtil.markDirtyAndRefresh(false, true, false, fs.refreshAndFindFileByPath(filePath), fs.refreshAndFindFileByPath(workspacePath)); - } - }, ModalityState.defaultModalityState()); - } - else { - myScheme = StorageScheme.DIRECTORY_BASED; - - final File dirStore = file.isDirectory() ? new File(file, Project.DIRECTORY_STORE_FOLDER) - : new File(file.getParentFile(), Project.DIRECTORY_STORE_FOLDER); - stateStorageManager.addMacro(StoragePathMacros.PROJECT_FILE, new File(dirStore, "misc.xml").getPath()); - - final File ws = new File(dirStore, "workspace.xml"); - stateStorageManager.addMacro(StoragePathMacros.WORKSPACE_FILE, ws.getPath()); - if (!ws.exists() && !file.isDirectory()) { - useOldWsContent(filePath, ws); - } - - stateStorageManager.addMacro(StoragePathMacros.PROJECT_CONFIG_DIR, dirStore.getPath()); - - ApplicationManager.getApplication().invokeAndWait(new Runnable() { - @Override - public void run() { - VfsUtil.markDirtyAndRefresh(false, true, true, fs.refreshAndFindFileByIoFile(dirStore)); - } - }, ModalityState.defaultModalityState()); - } - - myPresentableUrl = null; - } - - private static boolean isIprPath(final File file) { - return FileUtilRt.extensionEquals(file.getName(), ProjectFileType.DEFAULT_EXTENSION); - } - - private static String composeWsPath(String filePath) { - final int lastDot = filePath.lastIndexOf('.'); - final String filePathWithoutExt = lastDot > 0 ? filePath.substring(0, lastDot) : filePath; - return filePathWithoutExt + WorkspaceFileType.DOT_DEFAULT_EXTENSION; - } - - private static void useOldWsContent(final String filePath, final File ws) { - final File oldWs = new File(composeWsPath(filePath)); - if (oldWs.exists()) { - try { - final InputStream is = new FileInputStream(oldWs); - try { - final byte[] bytes = FileUtil.loadBytes(is, (int)oldWs.length()); - - final OutputStream os = new FileOutputStream(ws); - try { - os.write(bytes); - } - finally { - os.close(); - } - } - finally { - is.close(); - } - } - catch (IOException e) { - LOG.error(e); - } - } - } - - @Override - public VirtualFile getProjectBaseDir() { - if (myProject.isDefault()) return null; - - final String path = getProjectBasePath(); - if (path == null) return null; - - return LocalFileSystem.getInstance().findFileByPath(path); - } - - @Override - public String getProjectBasePath() { - if (myProject.isDefault()) return null; - - final String path = getProjectFilePath(); - if (!StringUtil.isEmptyOrSpaces(path)) { - return getBasePath(new File(path)); - } - - //we are not yet initialized completely ("open directory", etc) - StateStorage storage = getStateStorageManager().getStateStorage(StoragePathMacros.PROJECT_FILE, RoamingType.PER_USER); - if (!(storage instanceof FileBasedStorage)) { - return null; - } - - return getBasePath(((FileBasedStorage)storage).getFile()); - } - - private String getBasePath(@NotNull File file) { - if (myScheme == StorageScheme.DEFAULT) { - return file.getParent(); - } - else { - File parentFile = file.getParentFile(); - return parentFile == null ? null : parentFile.getParent(); - } - } - - @NotNull - @Override - public String getProjectName() { - if (myScheme == StorageScheme.DIRECTORY_BASED) { - final VirtualFile baseDir = getProjectBaseDir(); - assert baseDir != null : "scheme=" + myScheme + " project file=" + getProjectFilePath(); - - final VirtualFile ideaDir = baseDir.findChild(Project.DIRECTORY_STORE_FOLDER); - if (ideaDir != null && ideaDir.isValid()) { - final VirtualFile nameFile = ideaDir.findChild(ProjectImpl.NAME_FILE); - if (nameFile != null && nameFile.isValid()) { - try { - BufferedReader in = new BufferedReader(new InputStreamReader(nameFile.getInputStream(), CharsetToolkit.UTF8_CHARSET)); - try { - final String name = in.readLine(); - if (name != null && !name.isEmpty()) { - return name.trim(); - } - } - finally { - in.close(); - } - } - catch (IOException ignored) { } - } - } - - return baseDir.getName().replace(":", ""); - } - else { - String temp = PathUtilRt.getFileName(((FileBasedStorage)getProjectFileStorage()).getFilePath()); - FileType fileType = FileTypeManager.getInstance().getFileTypeByFileName(temp); - if (fileType instanceof ProjectFileType) { - temp = temp.substring(0, temp.length() - fileType.getDefaultExtension().length() - 1); - } - final int i = temp.lastIndexOf(File.separatorChar); - if (i >= 0) { - temp = temp.substring(i + 1, temp.length() - i + 1); - } - return temp; - } - } - - @NotNull - @Override - public StorageScheme getStorageScheme() { - return myScheme; - } - - @Override - public String getPresentableUrl() { - if (myProject.isDefault()) { - return null; - } - if (myPresentableUrl == null) { - String url = myScheme == StorageScheme.DIRECTORY_BASED ? getProjectBasePath() : getProjectFilePath(); - if (url != null) { - myPresentableUrl = FileUtil.toSystemDependentName(url); - } - } - return myPresentableUrl; - } - - @Override - public VirtualFile getProjectFile() { - return myProject.isDefault() ? null : ((FileBasedStorage)getProjectFileStorage()).getVirtualFile(); - } - - @NotNull - @Override - public String getProjectFilePath() { - return myProject.isDefault() ? "" : ((FileBasedStorage)getProjectFileStorage()).getFilePath(); - } - - @NotNull - private XmlElementStorage getProjectFileStorage() { - // XmlElementStorage if default project, otherwise FileBasedStorage - XmlElementStorage storage = (XmlElementStorage)getStateStorageManager().getStateStorage(StoragePathMacros.PROJECT_FILE, RoamingType.PER_USER); - assert storage != null; - return storage; - } - - @Override - public VirtualFile getWorkspaceFile() { - if (myProject.isDefault()) return null; - final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getStateStorage(StoragePathMacros.WORKSPACE_FILE, RoamingType.DISABLED); - assert storage != null; - return storage.getVirtualFile(); - } - - @Nullable - @Override - public String getWorkspaceFilePath() { - if (myProject.isDefault()) return null; - final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getStateStorage(StoragePathMacros.WORKSPACE_FILE, RoamingType.DISABLED); - assert storage != null; - return storage.getFilePath(); - } - - @Override - public void loadProjectFromTemplate(@NotNull ProjectImpl defaultProject) { - defaultProject.save(); - - Element element = ((DefaultProjectStoreImpl)defaultProject.getStateStore()).getStateCopy(); - if (element != null) { - getProjectFileStorage().setDefaultState(element); - } - } - - @NotNull - @Override - protected StateStorageManager createStateStorageManager() { - return new ProjectStateStorageManager(myPathMacroManager.createTrackingSubstitutor(), myProject); - } - - static class ProjectStorageData extends BaseStorageData { - protected final Project myProject; - - ProjectStorageData(final String rootElementName, Project project) { - super(rootElementName); - myProject = project; - } - - protected ProjectStorageData(ProjectStorageData storageData) { - super(storageData); - myProject = storageData.myProject; - } - - @Override - public StorageData clone() { - return new ProjectStorageData(this); - } - } - - static class WsStorageData extends ProjectStorageData { - WsStorageData(final String rootElementName, final Project project) { - super(rootElementName, project); - } - - private WsStorageData(final WsStorageData storageData) { - super(storageData); - } - - @Override - public StorageData clone() { - return new WsStorageData(this); - } - } - - static class IprStorageData extends ProjectStorageData { - IprStorageData(final String rootElementName, Project project) { - super(rootElementName, project); - } - - IprStorageData(final IprStorageData storageData) { - super(storageData); - } - - @Override - public void load(@NotNull Element rootElement, @Nullable PathMacroSubstitutor pathMacroSubstitutor, boolean intern) { - final String v = rootElement.getAttributeValue(VERSION_OPTION); - //noinspection AssignmentToStaticFieldFromInstanceMethod - originalVersion = v != null ? Integer.parseInt(v) : 0; - - if (originalVersion != ProjectManagerImpl.CURRENT_FORMAT_VERSION) { - convert(rootElement, originalVersion); - } - - super.load(rootElement, pathMacroSubstitutor, intern); - } - - @SuppressWarnings("UnusedParameters") - protected void convert(Element root, int originalVersion) { - } - - @Override - public StorageData clone() { - return new IprStorageData(this); - } - } - - @Override - protected final List doSave(@Nullable List saveSessions, @NotNull List> readonlyFiles, @Nullable List errors) { - beforeSave(readonlyFiles); - - super.doSave(saveSessions, readonlyFiles, errors); - - UnableToSaveProjectNotification[] notifications = - NotificationsManager.getNotificationsManager().getNotificationsOfType(UnableToSaveProjectNotification.class, myProject); - if (readonlyFiles.isEmpty()) { - if (notifications.length > 0) { - for (UnableToSaveProjectNotification notification : notifications) { - notification.expire(); - } - } - return errors; - } - - if (notifications.length > 0) { - throw new SaveCancelledException(); - } - - ReadonlyStatusHandler.OperationStatus status; - AccessToken token = ReadAction.start(); - try { - status = ReadonlyStatusHandler.getInstance(myProject).ensureFilesWritable(getFilesList(readonlyFiles)); - } - finally { - token.finish(); - } - - if (status.hasReadonlyFiles()) { - dropUnableToSaveProjectNotification(myProject, status.getReadonlyFiles()); - throw new SaveCancelledException(); - } - List> oldList = new ArrayList>(readonlyFiles); - readonlyFiles.clear(); - for (Pair entry : oldList) { - errors = executeSave(entry.first, readonlyFiles, errors); - } - - if (errors != null) { - CompoundRuntimeException.doThrow(errors); - } - - if (!readonlyFiles.isEmpty()) { - dropUnableToSaveProjectNotification(myProject, getFilesList(readonlyFiles)); - throw new SaveCancelledException(); - } - - return errors; - } - - private static void dropUnableToSaveProjectNotification(@NotNull Project project, @NotNull VirtualFile[] readOnlyFiles) { - UnableToSaveProjectNotification[] notifications = - NotificationsManager.getNotificationsManager().getNotificationsOfType(UnableToSaveProjectNotification.class, project); - if (notifications.length == 0) { - Notifications.Bus.notify(new UnableToSaveProjectNotification(project, readOnlyFiles), project); - } - else { - notifications[0].myFiles = readOnlyFiles; - } - } - - protected void beforeSave(@NotNull List> readonlyFiles) { - } - - @NotNull - private static VirtualFile[] getFilesList(List> readonlyFiles) { - final VirtualFile[] files = new VirtualFile[readonlyFiles.size()]; - for (int i = 0, size = readonlyFiles.size(); i < size; i++) { - files[i] = readonlyFiles.get(i).second; - } - return files; - } - - private final StateStorageChooser> myStateStorageChooser = new StateStorageChooser>() { - @NotNull - @Override - public Storage[] selectStorages(@NotNull Storage[] storages, @NotNull PersistentStateComponent component, @NotNull StateStorageOperation operation) { - if (operation == StateStorageOperation.READ) { - List result = new SmartList(); - for (int i = storages.length - 1; i >= 0; i--) { - Storage storage = storages[i]; - if (storage.scheme() == myScheme) { - result.add(storage); - } - } - - for (Storage storage : storages) { - if (storage.scheme() == StorageScheme.DEFAULT && !result.contains(storage)) { - result.add(storage); - } - } - - return result.toArray(new Storage[result.size()]); - } - else if (operation == StateStorageOperation.WRITE) { - List result = new SmartList(); - for (Storage storage : storages) { - if (storage.scheme() == myScheme) { - result.add(storage); - } - } - - if (!result.isEmpty()) { - return result.toArray(new Storage[result.size()]); - } - - for (Storage storage : storages) { - if (storage.scheme() == StorageScheme.DEFAULT) { - result.add(storage); - } - } - - return result.toArray(new Storage[result.size()]); - } - else { - return new Storage[]{}; - } - } - }; - - @Override - protected StateStorageChooser> getDefaultStateStorageChooser() { - return myStateStorageChooser; - } - - @NotNull - @Override - protected MessageBus getMessageBus() { - return myProject.getMessageBus(); - } - - @NotNull - @Override - protected Storage[] getComponentStorageSpecs(@NotNull PersistentStateComponent component, - @NotNull State stateSpec, - @NotNull StateStorageOperation operation) { - // if we create project from default, component state written not to own storage file, but to project file, - // we don't have time to fix it properly, so, ancient hack restored. - Storage[] result = super.getComponentStorageSpecs(component, stateSpec, operation); - // don't add fake storage if project file storage already listed, otherwise data will be deleted on write (because of "deprecated") - for (Storage storage : result) { - if (storage.file().equals(StoragePathMacros.PROJECT_FILE)) { - return result; - } - } - - Storage[] withProjectFileStorage = new Storage[result.length + 1]; - System.arraycopy(result, 0, withProjectFileStorage, 0, result.length); - withProjectFileStorage[result.length] = DEFAULT_STORAGE_ANNOTATION; - return withProjectFileStorage; - } - - @SuppressWarnings("ClassExplicitlyAnnotation") - private static class MyStorage implements Storage { - @Override - public String id() { - return "___Default___"; - } - - @Override - public boolean isDefault() { - return true; - } - - @Override - public String file() { - return StoragePathMacros.PROJECT_FILE; - } - - @Override - public StorageScheme scheme() { - return StorageScheme.DEFAULT; - } - - @Override - public boolean deprecated() { - return true; - } - - @Override - public RoamingType roamingType() { - return RoamingType.PER_USER; - } - - @Override - public Class storageClass() { - return StateStorage.class; - } - - @Override - public Class stateSplitter() { - return StateSplitterEx.class; - } - - @NotNull - @Override - public Class annotationType() { - throw new UnsupportedOperationException("Method annotationType not implemented in " + getClass()); - } - } -} diff --git a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ProjectWithModulesStoreImpl.java b/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ProjectWithModulesStoreImpl.java deleted file mode 100644 index 68a97cd0b2ce..000000000000 --- a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/ProjectWithModulesStoreImpl.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2000-2015 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. - */ -package com.intellij.openapi.components.impl.stores; - -import com.intellij.openapi.components.PathMacroManager; -import com.intellij.openapi.components.StateStorage; -import com.intellij.openapi.components.StateStorage.SaveSession; -import com.intellij.openapi.components.TrackingPathMacroSubstitutor; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.project.impl.ProjectImpl; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.SmartList; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NotNull; - -import java.util.List; -import java.util.Set; - -public class ProjectWithModulesStoreImpl extends ProjectStoreImpl { - public ProjectWithModulesStoreImpl(@NotNull ProjectImpl project, @NotNull PathMacroManager pathMacroManager) { - super(project, pathMacroManager); - } - - @Override - public boolean reinitComponent(@NotNull String componentName, @NotNull Set changedStorages) { - if (super.reinitComponent(componentName, changedStorages)) { - return true; - } - - for (Module module : getPersistentModules()) { - // we have to reinit all modules for component because we don't know affected module - getComponentStore(module).reinitComponent(componentName, changedStorages); - } - return true; - } - - @NotNull - private static IComponentStore getComponentStore(@NotNull Module module) { - return (IComponentStore)module.getPicoContainer().getComponentInstance(IComponentStore.class); - } - - @NotNull - @Override - public TrackingPathMacroSubstitutor[] getSubstitutors() { - List result = new SmartList(); - ContainerUtil.addIfNotNull(result, getStateStorageManager().getMacroSubstitutor()); - - for (Module module : getPersistentModules()) { - ContainerUtil.addIfNotNull(result, getComponentStore(module).getStateStorageManager().getMacroSubstitutor()); - } - - return result.toArray(new TrackingPathMacroSubstitutor[result.size()]); - } - - @Override - public boolean isReloadPossible(@NotNull Set componentNames) { - if (!super.isReloadPossible(componentNames)) { - return false; - } - - for (Module module : getPersistentModules()) { - if (!getComponentStore(module).isReloadPossible(componentNames)) { - return false; - } - } - - return true; - } - - @NotNull - protected Module[] getPersistentModules() { - ModuleManager moduleManager = ModuleManager.getInstance(myProject); - return moduleManager == null ? Module.EMPTY_ARRAY : moduleManager.getModules(); - } - - @Override - protected void beforeSave(@NotNull List> readonlyFiles) { - super.beforeSave(readonlyFiles); - - for (Module module : getPersistentModules()) { - getComponentStore(module).save(readonlyFiles); - } - } -} diff --git a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java b/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java deleted file mode 100644 index 71bd942fb47f..000000000000 --- a/platform/configuration-store-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Copyright 2000-2015 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. - */ -package com.intellij.openapi.components.impl.stores; - -import com.intellij.openapi.Disposable; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.components.*; -import com.intellij.openapi.components.StateStorage.SaveSession; -import com.intellij.openapi.components.StateStorageChooserEx.Resolution; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.Couple; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.RoamingTypeDisabled; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.PathUtilRt; -import com.intellij.util.ReflectionUtil; -import com.intellij.util.SmartList; -import com.intellij.util.containers.ContainerUtil; -import gnu.trove.THashMap; -import org.jdom.Element; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.picocontainer.MutablePicoContainer; -import org.picocontainer.PicoContainer; - -import java.io.File; -import java.util.*; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public abstract class StateStorageManagerImpl implements StateStorageManager, Disposable { - private static final Logger LOG = Logger.getInstance(StateStorageManagerImpl.class); - - private final Map myMacros = new LinkedHashMap(); - private final Lock myStorageLock = new ReentrantLock(); - private final Map myStorages = new THashMap(); - private final TrackingPathMacroSubstitutor myPathMacroSubstitutor; - private final String myRootTagName; - private final PicoContainer myPicoContainer; - - private StreamProvider myStreamProvider; - - public StateStorageManagerImpl(@NotNull TrackingPathMacroSubstitutor pathMacroSubstitutor, - @NotNull String rootTagName, - @NotNull Disposable parentDisposable, - @NotNull PicoContainer picoContainer) { - myPicoContainer = picoContainer; - myRootTagName = rootTagName; - myPathMacroSubstitutor = pathMacroSubstitutor; - Disposer.register(parentDisposable, this); - } - - @Override - public TrackingPathMacroSubstitutor getMacroSubstitutor() { - return myPathMacroSubstitutor; - } - - @Override - public synchronized void addMacro(@NotNull String macro, @NotNull String expansion) { - assert !macro.isEmpty(); - // backward compatibility - if (macro.charAt(0) != '$') { - LOG.warn("Add macros instead of macro name: " + macro); - expansion = '$' + macro + '$'; - } - myMacros.put(macro, expansion); - } - - @Nullable - protected final String getMacrosValue(@NotNull String macro) { - return myMacros.get(macro); - } - - @Override - @NotNull - public StateStorage getStateStorage(@NotNull Storage storageSpec) { - String key = storageSpec.storageClass().equals(StateStorage.class) ? storageSpec.file() : storageSpec.storageClass().getName(); - - myStorageLock.lock(); - try { - StateStorage stateStorage = myStorages.get(key); - if (stateStorage == null) { - stateStorage = createStateStorage(storageSpec.storageClass(), storageSpec.file(), storageSpec.roamingType(), storageSpec.stateSplitter()); - myStorages.put(key, stateStorage); - } - return stateStorage; - } - finally { - myStorageLock.unlock(); - } - } - - @Nullable - @Override - public StateStorage getStateStorage(@NotNull String fileSpec, @NotNull RoamingType roamingType) { - myStorageLock.lock(); - try { - StateStorage stateStorage = myStorages.get(fileSpec); - if (stateStorage == null) { - stateStorage = createStateStorage(StateStorage.class, fileSpec, roamingType, StateSplitterEx.class); - myStorages.put(fileSpec, stateStorage); - } - return stateStorage; - } - finally { - myStorageLock.unlock(); - } - } - - @NotNull - @Override - public Couple> getCachedFileStateStorages(@NotNull Collection changed, @NotNull Collection deleted) { - myStorageLock.lock(); - try { - return Couple.of(getCachedFileStorages(changed), getCachedFileStorages(deleted)); - } - finally { - myStorageLock.unlock(); - } - } - - @NotNull - Collection getCachedFileStorages(@NotNull Collection fileSpecs) { - if (fileSpecs.isEmpty()) { - return Collections.emptyList(); - } - - List result = null; - for (String fileSpec : fileSpecs) { - StateStorage storage = myStorages.get(fileSpec); - if (storage instanceof FileBasedStorage) { - if (result == null) { - result = new SmartList(); - } - result.add((FileBasedStorage)storage); - } - } - return result == null ? Collections.emptyList() : result; - } - - @NotNull - @Override - public Collection getStorageFileNames() { - myStorageLock.lock(); - try { - return myStorages.keySet(); - } - finally { - myStorageLock.unlock(); - } - } - - // overridden in upsource - protected StateStorage createStateStorage(@NotNull Class storageClass, - @NotNull String fileSpec, - @NotNull RoamingType roamingType, - @SuppressWarnings("deprecation") @NotNull Class stateSplitter) { - if (!storageClass.equals(StateStorage.class)) { - String key = UUID.randomUUID().toString(); - ((MutablePicoContainer)myPicoContainer).registerComponentImplementation(key, storageClass); - return (StateStorage)myPicoContainer.getComponentInstance(key); - } - - String filePath = expandMacros(fileSpec); - File file = new File(filePath); - - //noinspection deprecation - if (!stateSplitter.equals(StateSplitter.class) && !stateSplitter.equals(StateSplitterEx.class)) { - return new DirectoryBasedStorage(myPathMacroSubstitutor, file, ReflectionUtil.newInstance(stateSplitter), this, createStorageTopicListener()); - } - - if (!ApplicationManager.getApplication().isHeadlessEnvironment() && PathUtilRt.getFileName(filePath).lastIndexOf('.') < 0) { - throw new IllegalArgumentException("Extension is missing for storage file: " + filePath); - } - - if (roamingType == RoamingType.PER_USER && fileSpec.equals(StoragePathMacros.WORKSPACE_FILE)) { - roamingType = RoamingType.DISABLED; - } - - beforeFileBasedStorageCreate(); - return new FileBasedStorage(file, fileSpec, - roamingType, getMacroSubstitutor(fileSpec), myRootTagName, StateStorageManagerImpl.this, - createStorageTopicListener(), myStreamProvider) { - @Override - @NotNull - protected StorageData createStorageData() { - return StateStorageManagerImpl.this.createStorageData(myFileSpec, getFilePath()); - } - - @Override - protected boolean isUseXmlProlog() { - return StateStorageManagerImpl.this.isUseXmlProlog(); - } - }; - } - - @Override - public void clearStateStorage(@NotNull String file) { - myStorageLock.lock(); - try { - myStorages.remove(file); - } - finally { - myStorageLock.unlock(); - } - } - - @Nullable - protected StateStorage.Listener createStorageTopicListener() { - return null; - } - - protected boolean isUseXmlProlog() { - return true; - } - - protected void beforeFileBasedStorageCreate() { - } - - @Nullable - @Override - public final StreamProvider getStreamProvider() { - return myStreamProvider; - } - - protected TrackingPathMacroSubstitutor getMacroSubstitutor(@NotNull String fileSpec) { - return myPathMacroSubstitutor; - } - - @NotNull - protected abstract StorageData createStorageData(@NotNull String fileSpec, @NotNull String filePath); - - private static final Pattern MACRO_PATTERN = Pattern.compile("(\\$[^\\$]*\\$)"); - - @Override - @NotNull - public synchronized String expandMacros(@NotNull String file) { - Matcher matcher = MACRO_PATTERN.matcher(file); - while (matcher.find()) { - String m = matcher.group(1); - if (!myMacros.containsKey(m)) { - throw new IllegalArgumentException("Unknown macro: " + m + " in storage file spec: " + file); - } - } - - String expanded = file; - for (Map.Entry entry : myMacros.entrySet()) { - expanded = StringUtil.replace(expanded, entry.getKey(), entry.getValue()); - } - return expanded; - } - - @NotNull - @Override - public String collapseMacros(@NotNull String path) { - String result = path; - for (Map.Entry entry : myMacros.entrySet()) { - result = StringUtil.replace(result, entry.getValue(), entry.getKey()); - } - return result; - } - - @NotNull - @Override - public ExternalizationSession startExternalization() { - return new StateStorageManagerExternalizationSession(); - } - - protected class StateStorageManagerExternalizationSession implements ExternalizationSession { - private final Map mySessions = new LinkedHashMap(); - - @Override - public void setState(@NotNull Storage[] storageSpecs, @NotNull Object component, @NotNull String componentName, @NotNull Object state) { - StateStorageChooserEx stateStorageChooser = component instanceof StateStorageChooserEx ? (StateStorageChooserEx)component : null; - for (Storage storageSpec : storageSpecs) { - Resolution resolution = stateStorageChooser == null ? Resolution.DO : stateStorageChooser.getResolution(storageSpec, StateStorageOperation.WRITE); - if (resolution == Resolution.SKIP) { - continue; - } - - StateStorage stateStorage = getStateStorage(storageSpec); - StateStorage.ExternalizationSession session = getExternalizationSession(stateStorage); - if (session != null) { - // empty element as null state, so, will be deleted - session.setState(component, componentName, storageSpec.deprecated() || resolution == Resolution.CLEAR ? new Element("empty") : state, storageSpec); - } - } - } - - @Override - public void setStateInOldStorage(@NotNull Object component, @NotNull String componentName, @NotNull Object state) { - StateStorage stateStorage = getOldStorage(component, componentName, StateStorageOperation.WRITE); - if (stateStorage != null) { - StateStorage.ExternalizationSession session = getExternalizationSession(stateStorage); - if (session != null) { - session.setState(component, componentName, state, null); - } - } - } - - @Nullable - protected final StateStorage.ExternalizationSession getExternalizationSession(@NotNull StateStorage stateStorage) { - StateStorage.ExternalizationSession session = mySessions.get(stateStorage); - if (session == null) { - session = stateStorage.startExternalization(); - if (session != null) { - mySessions.put(stateStorage, session); - } - } - return session; - } - - @NotNull - @Override - public List createSaveSessions() { - if (mySessions.isEmpty()) { - return Collections.emptyList(); - } - - List saveSessions = null; - Collection externalizationSessions = mySessions.values(); - for (StateStorage.ExternalizationSession session : externalizationSessions) { - SaveSession saveSession = session.createSaveSession(); - if (saveSession != null) { - if (saveSessions == null) { - if (externalizationSessions.size() == 1) { - return Collections.singletonList(saveSession); - } - saveSessions = new SmartList(); - } - saveSessions.add(saveSession); - } - } - return ContainerUtil.notNullize(saveSessions); - } - } - - @Override - @Nullable - public StateStorage getOldStorage(@NotNull Object component, @NotNull String componentName, @NotNull StateStorageOperation operation) { - String oldStorageSpec = getOldStorageSpec(component, componentName, operation); - //noinspection deprecation - return oldStorageSpec == null ? null : getStateStorage(oldStorageSpec, component instanceof RoamingTypeDisabled ? RoamingType.DISABLED : RoamingType.PER_USER); - } - - @Nullable - protected abstract String getOldStorageSpec(@NotNull Object component, @NotNull String componentName, @NotNull StateStorageOperation operation); - - @Override - public void dispose() { - } - - @Override - public void setStreamProvider(@Nullable StreamProvider streamProvider) { - myStreamProvider = streamProvider; - } -} diff --git a/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt b/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt index 92373f89fb91..1a7e96549d15 100644 --- a/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt +++ b/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt @@ -19,13 +19,14 @@ import com.intellij.application.options.PathMacrosImpl import com.intellij.openapi.Disposable import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.* -import com.intellij.openapi.components.impl.ApplicationPathMacroManager -import com.intellij.openapi.components.impl.stores.* +import com.intellij.openapi.components.impl.stores.StateStorageManager +import com.intellij.openapi.components.impl.stores.StorageData +import com.intellij.openapi.components.impl.stores.StoreUtil +import com.intellij.openapi.components.impl.stores.StreamProvider import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.vfs.CharsetToolkit import com.intellij.testFramework.LightPlatformTestCase -import com.intellij.util.messages.MessageBus import com.intellij.util.xmlb.XmlSerializerUtil import gnu.trove.THashMap import org.hamcrest.CoreMatchers.equalTo @@ -40,7 +41,6 @@ public class ApplicationStoreTest : LightPlatformTestCase() { private var testAppConfig: File? = null private var componentStore: MyComponentStore? = null - throws(Exception::class) override fun setUp() { super.setUp() @@ -56,7 +56,6 @@ public class ApplicationStoreTest : LightPlatformTestCase() { componentStore = MyComponentStore(testAppConfig!!.getAbsolutePath()) } - throws(Exception::class) override fun tearDown() { try { Disposer.dispose(componentStore!!) @@ -119,7 +118,6 @@ public class ApplicationStoreTest : LightPlatformTestCase() { assertThat(oldFile.exists(), equalTo(false)) } - throws(IOException::class) private fun saveConfig(fileName: String, Language("XML") data: String): File { val file = File(testAppConfig, fileName) FileUtil.writeToFile(file, data) @@ -160,16 +158,12 @@ public class ApplicationStoreTest : LightPlatformTestCase() { init { val macroSubstitutor = ApplicationPathMacroManager().createTrackingSubstitutor() stateStorageManager = object : StateStorageManagerImpl(macroSubstitutor, "application", this, ApplicationManager.getApplication().getPicoContainer()) { - override fun createStorageData(fileSpec: String, filePath: String): StorageData { - return StorageData("application") - } + override fun createStorageData(fileSpec: String, filePath: String) = StorageData("application") - override fun getOldStorageSpec(component: Any, componentName: String, operation: StateStorageOperation): String? { - return null - } + override fun getOldStorageSpec(component: Any, componentName: String, operation: StateStorageOperation) = null override fun getMacroSubstitutor(fileSpec: String): TrackingPathMacroSubstitutor? { - if (fileSpec == StoragePathMacros.APP_CONFIG + "/" + PathMacrosImpl.EXT_FILE_NAME + ".xml") { + if (fileSpec == "${StoragePathMacros.APP_CONFIG}/${PathMacrosImpl.EXT_FILE_NAME}.xml") { return null } return super.getMacroSubstitutor(fileSpec) @@ -179,16 +173,12 @@ public class ApplicationStoreTest : LightPlatformTestCase() { stateStorageManager.addMacro(StoragePathMacros.APP_CONFIG, testAppConfigPath) } - override fun getStateStorageManager(): StateStorageManager { - return stateStorageManager - } + override fun getStateStorageManager() = stateStorageManager override fun dispose() { } - override fun getMessageBus(): MessageBus { - return ApplicationManager.getApplication().getMessageBus() - } + override fun getMessageBus() = ApplicationManager.getApplication().getMessageBus() } abstract class Foo { @@ -208,9 +198,7 @@ public class ApplicationStoreTest : LightPlatformTestCase() { State(name = "HttpConfigurable", storages = arrayOf(Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml", deprecated = true), Storage(file = StoragePathMacros.APP_CONFIG + "/proxy.settings.xml"))) class ActualStorageLast : Foo(), PersistentStateComponent { - override fun getState(): ActualStorageLast? { - return this - } + override fun getState() = this override fun loadState(state: ActualStorageLast) { XmlSerializerUtil.copyBean(state, this) diff --git a/platform/configuration-store-impl/testSrc/com/intellij/openapi/components/impl/StateStorageManagerImplTest.java b/platform/configuration-store-impl/testSrc/com/intellij/openapi/components/impl/StateStorageManagerImplTest.java deleted file mode 100644 index 9e0beb723bb7..000000000000 --- a/platform/configuration-store-impl/testSrc/com/intellij/openapi/components/impl/StateStorageManagerImplTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2000-2015 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. - */ -package com.intellij.openapi.components.impl; - -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.components.*; -import com.intellij.openapi.components.impl.stores.StateStorageManagerImpl; -import com.intellij.openapi.components.impl.stores.StorageData; -import com.intellij.openapi.util.Disposer; -import com.intellij.testFramework.LightPlatformTestCase; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.junit.Assert.assertThat; - -/** - * @author mike - */ -public class StateStorageManagerImplTest extends LightPlatformTestCase { - private StateStorageManagerImpl myStateStorageManager; - - @Override - public final void setUp() throws Exception { - super.setUp(); - TrackingPathMacroSubstitutor substitutor = PathMacroManager.getInstance(getProject()).createTrackingSubstitutor(); - myStateStorageManager = new StateStorageManagerImpl(substitutor, "foo", myTestRootDisposable, ApplicationManager.getApplication().getPicoContainer()) { - @NotNull - @Override - protected StorageData createStorageData(@NotNull String fileSpec, @NotNull String filePath) { - throw new UnsupportedOperationException("Method createStorageData not implemented in " + getClass()); - } - - @Nullable - @Override - protected String getOldStorageSpec(@NotNull Object component, @NotNull String componentName, @NotNull StateStorageOperation operation) { - throw new UnsupportedOperationException("Method getOldStorageSpec not implemented in " + getClass()); - } - }; - myStateStorageManager.addMacro("$MACRO1$", "/temp/m1"); - } - - @Override - public void tearDown() throws Exception { - Disposer.dispose(myStateStorageManager); - super.tearDown(); - } - - public void testCreateFileStateStorageMacroSubstituted() { - StateStorage data = myStateStorageManager.getStateStorage("$MACRO1$/test.xml", RoamingType.PER_USER); - assertThat(data, is(notNullValue())); - } - - public void testCreateStateStorageAssertionThrownWhenUnknownMacro() { - try { - myStateStorageManager.getStateStorage("$UNKNOWN_MACRO$/test.xml", RoamingType.PER_USER); - fail("Exception expected"); - } - catch (IllegalArgumentException e) { - assertEquals("Unknown macro: $UNKNOWN_MACRO$ in storage file spec: $UNKNOWN_MACRO$/test.xml", e.getMessage()); - } - } - - public void testCreateFileStateStorageMacroSubstitutedWhenExpansionHas$() { - myStateStorageManager.addMacro("$DOLLAR_MACRO$", "/temp/d$"); - StateStorage data = myStateStorageManager.getStateStorage("$DOLLAR_MACRO$/test.xml", RoamingType.PER_USER); - assertThat(data, is(notNullValue())); - } -} diff --git a/platform/configuration-store-impl/testSrc/com/intellij/openapi/components/impl/StateStorageManagerImplTest.kt b/platform/configuration-store-impl/testSrc/com/intellij/openapi/components/impl/StateStorageManagerImplTest.kt new file mode 100644 index 000000000000..7a2fa5d93ccb --- /dev/null +++ b/platform/configuration-store-impl/testSrc/com/intellij/openapi/components/impl/StateStorageManagerImplTest.kt @@ -0,0 +1,86 @@ +/* + * Copyright 2000-2015 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. + */ +package com.intellij.openapi.components.impl + +import com.intellij.configurationStore.StateStorageManagerImpl +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.components.PathMacroManager +import com.intellij.openapi.components.RoamingType +import com.intellij.openapi.components.StateStorage +import com.intellij.openapi.components.StateStorageOperation +import com.intellij.openapi.components.impl.stores.StorageData +import com.intellij.openapi.util.Disposer +import com.intellij.testFramework.LightPlatformTestCase +import junit.framework.TestCase +import org.hamcrest.CoreMatchers.`is` +import org.hamcrest.CoreMatchers.notNullValue +import org.junit.Assert.assertThat + +/** + * @author mike + */ +public class StateStorageManagerImplTest : LightPlatformTestCase() { + private var myStateStorageManager: StateStorageManagerImpl? = null + + override fun setUp() { + super.setUp() + val substitutor = PathMacroManager.getInstance(LightPlatformTestCase.getProject()).createTrackingSubstitutor() + myStateStorageManager = object : StateStorageManagerImpl(substitutor, "foo", myTestRootDisposable, ApplicationManager.getApplication().getPicoContainer()) { + override fun createStorageData(fileSpec: String, filePath: String): StorageData { + throw UnsupportedOperationException("Method createStorageData not implemented in " + javaClass) + } + + override fun getOldStorageSpec(component: Any, componentName: String, operation: StateStorageOperation): String? { + throw UnsupportedOperationException("Method getOldStorageSpec not implemented in " + javaClass) + } + } + myStateStorageManager!!.addMacro("\$MACRO1$", "/temp/m1") + } + + override fun tearDown() { + try { + val storageManager = myStateStorageManager + if (storageManager != null) { + Disposer.dispose(storageManager) + } + } + finally { + super.tearDown() + } + } + + public fun testCreateFileStateStorageMacroSubstituted() { + val data = myStateStorageManager!!.getStateStorage("\$MACRO1$/test.xml", RoamingType.PER_USER) + assertThat(data, `is`(notNullValue())) + } + + public fun testCreateStateStorageAssertionThrownWhenUnknownMacro() { + try { + myStateStorageManager!!.getStateStorage("\$UNKNOWN_MACRO$/test.xml", RoamingType.PER_USER) + TestCase.fail("Exception expected") + } + catch (e: IllegalArgumentException) { + TestCase.assertEquals("Unknown macro: \$UNKNOWN_MACRO$ in storage file spec: \$UNKNOWN_MACRO$/test.xml", e.getMessage()) + } + + } + + public fun `testCreateFileStateStorageMacroSubstitutedWhenExpansionHas$`() { + myStateStorageManager!!.addMacro("\$DOLLAR_MACRO$", "/temp/d$") + val data = myStateStorageManager!!.getStateStorage("\$DOLLAR_MACRO$/test.xml", RoamingType.PER_USER) + assertThat(data, `is`(notNullValue())) + } +} diff --git a/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndex.java index 0995346a4686..fb08cd7ac3d7 100644 --- a/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/indexing-api/src/com/intellij/util/indexing/FileBasedIndex.java @@ -21,8 +21,11 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ContentIterator; +import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileVisitor; import com.intellij.openapi.vfs.VirtualFileWithId; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.Consumer; @@ -145,6 +148,32 @@ public abstract class FileBasedIndex implements BaseComponent { return processAllKeys(indexId, processor, scope.getProject()); } + public static void iterateRecursively(@Nullable final VirtualFile root, + @NotNull final ContentIterator processor, + @Nullable final ProgressIndicator indicator, + @Nullable final Set visitedRoots, + @Nullable final ProjectFileIndex projectFileIndex) { + if (root == null) { + return; + } + + VfsUtilCore.visitChildrenRecursively(root, new VirtualFileVisitor() { + @Override + public boolean visitFile(@NotNull VirtualFile file) { + if (visitedRoots != null && !root.equals(file) && file.isDirectory() && !visitedRoots.add(file)) { + return false; // avoid visiting files more than once, e.g. additional indexed roots intersect sometimes + } + if (projectFileIndex != null && projectFileIndex.isExcluded(file)) { + return false; + } + if (indicator != null) indicator.checkCanceled(); + + processor.processFile(file); + return true; + } + }); + } + public interface ValueProcessor { /** * @param value a value to process diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/BetterPrefixMatcher.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/BetterPrefixMatcher.java index a0874a670de5..2a84a4200405 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/BetterPrefixMatcher.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/BetterPrefixMatcher.java @@ -18,18 +18,24 @@ package com.intellij.codeInsight.completion.impl; import com.intellij.codeInsight.completion.CompletionResult; import com.intellij.codeInsight.completion.CompletionResultSet; import com.intellij.codeInsight.completion.PrefixMatcher; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.codeStyle.MinusculeMatcher; +import com.intellij.util.containers.FList; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author peter */ public class BetterPrefixMatcher extends PrefixMatcher { private final PrefixMatcher myOriginal; + @Nullable private final CamelHumpMatcher myHumpMatcher; private final int myMinMatchingDegree; public BetterPrefixMatcher(PrefixMatcher original, int minMatchingDegree) { super(original.getPrefix()); myOriginal = original; + myHumpMatcher = original instanceof CamelHumpMatcher ? (CamelHumpMatcher)original : null; myMinMatchingDegree = minMatchingDegree; } @@ -47,6 +53,14 @@ public class BetterPrefixMatcher extends PrefixMatcher { @Override public boolean prefixMatches(@NotNull String name) { + if (myHumpMatcher != null) { + FList fragments = myHumpMatcher.matchingFragments(name); + if (fragments == null || !MinusculeMatcher.isStartMatch(fragments)) { + return false; + } + return myHumpMatcher.matchingDegree(name, fragments) >= myMinMatchingDegree; + } + if (!myOriginal.prefixMatches(name) || !myOriginal.isStartMatch(name)) { return false; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java index 6ddd60c02fd6..9b59c4a6ece0 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java @@ -1,4 +1,3 @@ - package com.intellij.codeInsight.completion.impl; import com.intellij.codeInsight.CodeInsightSettings; @@ -15,6 +14,7 @@ import com.intellij.psi.codeStyle.NameUtil; import com.intellij.util.containers.FList; import com.intellij.util.text.CharArrayUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; /** @@ -139,15 +139,25 @@ public class CamelHumpMatcher extends PrefixMatcher { @Override public int matchingDegree(String string) { - FList ranges = myCaseInsensitiveMatcher.matchingFragments(string); - if (ranges != null && !ranges.isEmpty()) { - int matchStart = ranges.get(0).getStartOffset(); - int underscoreEnd = skipUnderscores(string); - if (matchStart > 0 && matchStart <= underscoreEnd) { - return myCaseInsensitiveMatcher.matchingDegree(string.substring(matchStart), true) - 1; + return matchingDegree(string, matchingFragments(string)); + } + + public FList matchingFragments(String string) { + return myMatcher.matchingFragments(string); + } + + public int matchingDegree(String string, @Nullable FList fragments) { + int underscoreEnd = skipUnderscores(string); + if (underscoreEnd > 0) { + FList ciRanges = myCaseInsensitiveMatcher.matchingFragments(string); + if (ciRanges != null && !ciRanges.isEmpty()) { + int matchStart = ciRanges.get(0).getStartOffset(); + if (matchStart > 0 && matchStart <= underscoreEnd) { + return myCaseInsensitiveMatcher.matchingDegree(string.substring(matchStart), true) - 1; + } } } - return myMatcher.matchingDegree(string, true); + return myMatcher.matchingDegree(string, true, fragments); } } diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/DefaultChooseByNameItemProvider.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/DefaultChooseByNameItemProvider.java index cc5915c26bb6..0f9540af8d76 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/DefaultChooseByNameItemProvider.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/DefaultChooseByNameItemProvider.java @@ -22,6 +22,7 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressIndicatorProvider; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiCompiledElement; import com.intellij.psi.PsiElement; @@ -31,6 +32,7 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.proximity.PsiProximityComparator; import com.intellij.util.*; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.FList; import com.intellij.util.indexing.FindSymbolParameters; import com.intellij.util.indexing.IdFilter; import org.jetbrains.annotations.NotNull; @@ -373,7 +375,8 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider return null; // no matches appears valid result for "bad" pattern } } - return matcher.matches(name) ? new MatchResult(name, matcher.matchingDegree(name), matcher.isStartMatch(name)) : null; + FList fragments = matcher.matchingFragments(name); + return fragments != null ? new MatchResult(name, matcher.matchingDegree(name, false, fragments), MinusculeMatcher.isStartMatch(fragments)) : null; } @NotNull diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index a36edaf6657e..e1be3e368c38 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -2652,32 +2652,6 @@ public class FileBasedIndexImpl extends FileBasedIndex { return tasks; } - private static void iterateRecursively(@Nullable final VirtualFile root, - @NotNull final ContentIterator processor, - @Nullable final ProgressIndicator indicator, - @Nullable final Set visitedRoots, - @Nullable final ProjectFileIndex projectFileIndex) { - if (root == null) { - return; - } - - VfsUtilCore.visitChildrenRecursively(root, new VirtualFileVisitor() { - @Override - public boolean visitFile(@NotNull VirtualFile file) { - if (visitedRoots != null && !root.equals(file) && file.isDirectory() && !visitedRoots.add(file)) { - return false; // avoid visiting files more than once, e.g. additional indexed roots intersect sometimes - } - if (projectFileIndex != null && projectFileIndex.isExcluded(file)) { - return false; - } - if (indicator != null) indicator.checkCanceled(); - - processor.processFile(file); - return true; - } - }); - } - @SuppressWarnings({"WhileLoopSpinsOnField", "SynchronizeOnThis"}) private static class StorageGuard { private int myHolds = 0; diff --git a/platform/platform-api/src/com/intellij/openapi/ui/LoadingDecorator.java b/platform/platform-api/src/com/intellij/openapi/ui/LoadingDecorator.java index 3c2efa26ebd9..ea508b8e2b92 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/LoadingDecorator.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/LoadingDecorator.java @@ -239,7 +239,16 @@ public class LoadingDecorator { @Override public Dimension getMinimumSize() { - return myContent != null ? myContent.getMinimumSize() : super.getMinimumSize(); + return myContent != null && !isMinimumSizeSet() + ? myContent.getMinimumSize() + : super.getMinimumSize(); + } + + @Override + public Dimension getPreferredSize() { + return myContent != null && !isPreferredSizeSet() + ? myContent.getPreferredSize() + : super.getPreferredSize(); } @Override diff --git a/platform/platform-impl/src/com/intellij/ide/actions/ExportSettingsAction.java b/platform/platform-impl/src/com/intellij/ide/actions/ExportSettingsAction.java index 376a03fb76b8..a8123e12bb9e 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/ExportSettingsAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/ExportSettingsAction.java @@ -204,7 +204,6 @@ public class ExportSettingsAction extends AnAction implements DumbAware { storage.scheme() == StorageScheme.DEFAULT && !StringUtil.isEmpty(storage.file()) && storage.file().startsWith(StoragePathMacros.APP_CONFIG)) { - File file = new File(storageManager.expandMacros(storage.file())); File additionalExportFile = null; if (!StringUtil.isEmpty(stateAnnotation.additionalExportFile())) { @@ -219,6 +218,7 @@ public class ExportSettingsAction extends AnAction implements DumbAware { } } + File file = new File(storageManager.expandMacros(storage.file())); boolean fileExists = !onlyExisting || file.exists(); if (fileExists || additionalExportFile != null) { File[] files; diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java index e0bb2b11a606..3fd5dd35b8ba 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java @@ -74,6 +74,7 @@ import java.io.IOException; import java.net.URL; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import static com.intellij.openapi.util.text.StringUtil.isEmptyOrSpaces; @@ -326,7 +327,7 @@ public abstract class PluginManagerMain implements Disposable { @Override public void run() { final List list = ContainerUtil.newArrayList(); - final List errors = ContainerUtil.newSmartList(); + final Map errors = ContainerUtil.newLinkedHashMap(); ProgressIndicator indicator = new EmptyProgressIndicator(); List hosts = RepositoryHelper.getPluginHosts(); @@ -348,7 +349,7 @@ public abstract class PluginManagerMain implements Disposable { catch (IOException e) { LOG.info(host, e); if (host != ApplicationInfoEx.getInstanceEx().getBuiltinPluginsUrl()) { - errors.add(String.format("'%s' for '%s'", e.getMessage(), host)); + errors.put(host, String.format("'%s' for '%s'", e.getMessage(), host)); } } } @@ -369,7 +370,9 @@ public abstract class PluginManagerMain implements Disposable { } if (!errors.isEmpty()) { - String message = IdeBundle.message("error.list.of.plugins.was.not.loaded", StringUtil.join(errors, ", ")); + String message = IdeBundle.message("error.list.of.plugins.was.not.loaded", + StringUtil.join(errors.keySet(), ", "), + StringUtil.join(errors.values(), ",\n")); String title = IdeBundle.message("title.plugins"); String ok = CommonBundle.message("button.retry"), cancel = CommonBundle.getCancelButtonText(); if (Messages.showOkCancelDialog(message, title, ok, cancel, Messages.getErrorIcon()) == Messages.OK) { diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IProjectStore.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IProjectStore.java index 0cae75c1d492..c0252969ab57 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IProjectStore.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IProjectStore.java @@ -26,8 +26,6 @@ import org.jetbrains.annotations.Nullable; * @see com.intellij.openapi.project.ex.ProjectEx#getStateStore() */ public interface IProjectStore extends IComponentStore { - boolean checkVersion(); - void setProjectFilePath(@NotNull String filePath); @Nullable diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeVersion.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeVersion.java index f2194713a595..099420ee2c9e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeVersion.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeVersion.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -32,12 +32,12 @@ import com.intellij.openapi.project.ex.ProjectManagerEx; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.projectImport.ProjectOpenProcessor; +import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.util.Collection; -import java.util.HashSet; import java.util.Set; public interface MergeVersion { @@ -120,12 +120,12 @@ public interface MergeVersion { } @Nullable - public static Runnable prepareToReportChangedProjectFiles(@NotNull final Project project, final Collection files) { - final Set vfs = new HashSet(); - for (VirtualFile vf : files) { - if (vf != null && ! vf.isDirectory()) { - if (ProjectCoreUtil.isProjectOrWorkspaceFile(vf) || isProjectFile(vf)) { - vfs.add(vf); + public static Runnable prepareToReportChangedProjectFiles(@NotNull final Project project, @NotNull Collection files) { + final Set vfs = new THashSet(); + for (VirtualFile file : files) { + if (file != null && !file.isDirectory()) { + if (ProjectCoreUtil.isProjectOrWorkspaceFile(file) || isProjectFile(file)) { + vfs.add(file); } } } @@ -168,8 +168,7 @@ public interface MergeVersion { @Override public byte[] getBytes() throws IOException { VirtualFile file = getFile(); - if (file != null) return file.contentsToByteArray(); - return myDocument.getText().getBytes(); + return file != null ? file.contentsToByteArray() : myDocument.getText().getBytes(); } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsEditor.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsEditor.java index 68a924f6551e..752b84941baf 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsEditor.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsEditor.java @@ -191,6 +191,7 @@ final class SettingsEditor extends AbstractEditor implements DataProvider { mySettings.select(configurable); } }; + myEditor.setPreferredSize(JBUI.size(800, 600)); myLoadingDecorator = new LoadingDecorator(myEditor, this, 10, true); myBanner = new Banner(myEditor.getResetAction()); mySearchPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java index 97208bb9feda..7241af11f500 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java @@ -79,8 +79,6 @@ import java.util.concurrent.atomic.AtomicInteger; public class ProjectManagerImpl extends ProjectManagerEx implements PersistentStateComponent, ExportableApplicationComponent { private static final Logger LOG = Logger.getInstance(ProjectManagerImpl.class); - public static final int CURRENT_FORMAT_VERSION = 4; - private static final Key> LISTENERS_IN_PROJECT_KEY = Key.create("LISTENERS_IN_PROJECT_KEY"); private static final Key> CHANGED_FILES_KEY = Key.create("CHANGED_FILES_KEY"); @@ -427,13 +425,10 @@ public class ProjectManagerImpl extends ProjectManagerEx implements PersistentSt } } - final Application application = ApplicationManager.getApplication(); - if (!application.isUnitTestMode() && !((ProjectEx)project).getStateStore().checkVersion()) { + if (!addToOpened(project)) { return false; } - if (!addToOpened(project)) return false; - fireProjectOpened(project); DumbService.getInstance(project).queueTask(new DumbModeTask() { @Override @@ -1003,9 +998,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements PersistentSt @Override public void loadState(Element state) { myDefaultProjectRootElement = state.getChild("defaultProject"); - if (myDefaultProjectRootElement != null) { - myDefaultProjectRootElement.detach(); - } + if (myDefaultProjectRootElement != null) myDefaultProjectRootElement.detach(); myDefaultProjectConfigurationChanged = false; } diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index c5fcd9447644..6bf09e2eb6e7 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -517,7 +517,7 @@ ide.postpone.action=Postpone title.plugins=Plugins title.plugins.changed=Plugins Changed plugin.status.not.specified=(not specified) -error.list.of.plugins.was.not.loaded=Unable to update the list of plugins due to the following error: {0} +error.list.of.plugins.was.not.loaded=List of plugins was not loaded for following hosts: {0}\n\nDue to the following errors:\n{1} action.download.and.install.plugin=Download and Install action.update.plugin=Update Plugin error.plugin.download.failed=Plugin download failed diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index f137a0fdea50..e61038b86e60 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -327,7 +327,7 @@ - + diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index 2aa9f08d34bc..f7085b0139c9 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -7,9 +7,9 @@ + serviceImplementation="com.intellij.configurationStore.ApplicationStoreImpl"/> + serviceImplementation="com.intellij.configurationStore.ApplicationPathMacroManager"/> com.intellij.openapi.project.impl.ProjectStoreClassProvider - com.intellij.openapi.components.impl.stores.PlatformProjectStoreClassProvider + com.intellij.configurationStore.PlatformProjectStoreClassProvider diff --git a/platform/platform-resources/src/componentSets/PlatformLangComponents.xml b/platform/platform-resources/src/componentSets/PlatformLangComponents.xml index dc70e3968008..71a06a1b1b8f 100644 --- a/platform/platform-resources/src/componentSets/PlatformLangComponents.xml +++ b/platform/platform-resources/src/componentSets/PlatformLangComponents.xml @@ -13,7 +13,7 @@ com.intellij.openapi.project.impl.ProjectStoreClassProvider - com.intellij.openapi.components.impl.stores.PlatformLangProjectStoreClassProvider + com.intellij.configurationStore.PlatformLangProjectStoreClassProvider diff --git a/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/StorageData.java b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/StorageData.java index 02eccd2fad3e..7b99fb2a1d8b 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/StorageData.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/StorageData.java @@ -55,7 +55,7 @@ public class StorageData extends StorageDataBase { myRootElementName = rootElementName; } - StorageData(@NotNull StorageData storageData) { + protected StorageData(@NotNull StorageData storageData) { myRootElementName = storageData.myRootElementName; myStates = new StateMap(storageData.myStates); } diff --git a/platform/testFramework/src/com/intellij/mock/MockProjectStore.java b/platform/testFramework/src/com/intellij/mock/MockProjectStore.java index 8d52d4a36983..6343f2f161e5 100644 --- a/platform/testFramework/src/com/intellij/mock/MockProjectStore.java +++ b/platform/testFramework/src/com/intellij/mock/MockProjectStore.java @@ -36,11 +36,6 @@ import java.util.Set; * @author peter */ public class MockProjectStore implements IProjectStore { - @Override - public boolean checkVersion() { - throw new UnsupportedOperationException("Method checkVersion is not yet implemented in " + getClass().getName()); - } - @Override public void setProjectFilePath(@NotNull final String filePath) { throw new UnsupportedOperationException("Method setProjectFilePath is not yet implemented in " + getClass().getName()); diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index 22f9ddf33243..13a3761167f8 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -1943,7 +1943,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig @Override public void assertPreferredCompletionItems(final int selected, @NotNull @NonNls final String... expected) { final LookupImpl lookup = getLookup(); - Assert.assertNotNull(lookup); + Assert.assertNotNull("No lookup is shown", lookup); final JList list = lookup.getList(); List strings = getLookupElementStrings(); diff --git a/platform/util/src/com/intellij/psi/codeStyle/MinusculeMatcher.java b/platform/util/src/com/intellij/psi/codeStyle/MinusculeMatcher.java index aa9f813a5694..df79f2e2c420 100644 --- a/platform/util/src/com/intellij/psi/codeStyle/MinusculeMatcher.java +++ b/platform/util/src/com/intellij/psi/codeStyle/MinusculeMatcher.java @@ -162,11 +162,14 @@ public class MinusculeMatcher implements Matcher { } public int matchingDegree(@NotNull String name, boolean valueStartCaseMatch) { - FList iterable = matchingFragments(name); - if (iterable == null) return Integer.MIN_VALUE; - if (iterable.isEmpty()) return 0; + return matchingDegree(name, valueStartCaseMatch, matchingFragments(name)); + } - final TextRange first = iterable.getHead(); + public int matchingDegree(@NotNull String name, boolean valueStartCaseMatch, @Nullable FList fragments) { + if (fragments == null) return Integer.MIN_VALUE; + if (fragments.isEmpty()) return 0; + + final TextRange first = fragments.getHead(); boolean startMatch = first.getStartOffset() == 0; int matchingCase = 0; @@ -175,7 +178,7 @@ public class MinusculeMatcher implements Matcher { int integral = 0; // -sum of matching-char-count * hump-index over all matched humps; favors longer fragments matching earlier words int humpIndex = 1; int nextHumpStart = 0; - for (TextRange range : iterable) { + for (TextRange range : fragments) { for (int i = range.getStartOffset(); i < range.getEndOffset(); i++) { boolean isHumpStart = false; while (nextHumpStart <= i) { @@ -198,7 +201,7 @@ public class MinusculeMatcher implements Matcher { if (c == myPattern[p]) { if (isUpperCase[p]) matchingCase += 50; // strongly prefer user's uppercase matching uppercase: they made an effort to press Shift else if (i == 0 && startMatch) matchingCase += 15; // the very first letter case distinguishes classes in Java etc - else if (isHumpStart) matchingCase += 1; // if a lowercase matches lowercase hump start, that also means something + else if (isHumpStart) matchingCase += 1; // if a lowercase matches lowercase hump start, that also means something } else if (isHumpStart) { // disfavor hump starts where pattern letter case doesn't match name case matchingCase -= 1; @@ -209,25 +212,24 @@ public class MinusculeMatcher implements Matcher { int startIndex = first.getStartOffset(); boolean afterSeparator = StringUtil.indexOfAny(name, myHardSeparators, 0, startIndex) >= 0; boolean wordStart = startIndex == 0 || isWordStart(name, startIndex) && !isWordStart(name, startIndex - 1); - boolean finalMatch = iterable.get(iterable.size() - 1).getEndOffset() == name.length(); + boolean finalMatch = fragments.get(fragments.size() - 1).getEndOffset() == name.length(); - return (wordStart ? 1000 : 0) + - integral * 10 + + return (wordStart ? 1000 : 0) + + integral * 10 + matchingCase * (startMatch && valueStartCaseMatch ? 10 : 1) + - (afterSeparator ? 0 : 2) + + (afterSeparator ? 0 : 2) + (startMatch ? 1 : 0) + (finalMatch ? 1 : 0); } public boolean isStartMatch(@NotNull String name) { - Iterable fragments = matchingFragments(name); - if (fragments != null) { - Iterator iterator = fragments.iterator(); - if (!iterator.hasNext() || iterator.next().getStartOffset() == 0) { - return true; - } - } - return false; + FList fragments = matchingFragments(name); + return fragments != null && isStartMatch(fragments); + } + + public static boolean isStartMatch(@NotNull Iterable fragments) { + Iterator iterator = fragments.iterator(); + return !iterator.hasNext() || iterator.next().getStartOffset() == 0; } @Override diff --git a/platform/vcs-api/src/com/intellij/vcsUtil/VcsUtil.java b/platform/vcs-api/src/com/intellij/vcsUtil/VcsUtil.java index bae5b5dfd833..5f5757ec0316 100644 --- a/platform/vcs-api/src/com/intellij/vcsUtil/VcsUtil.java +++ b/platform/vcs-api/src/com/intellij/vcsUtil/VcsUtil.java @@ -319,7 +319,7 @@ public class VcsUtil { return VcsContextFactory.SERVICE.getInstance().createFilePathOn(file); } - public static FilePath getFilePath(File file) { + public static FilePath getFilePath(@NotNull File file) { return VcsContextFactory.SERVICE.getInstance().createFilePathOn(file); } @@ -331,11 +331,11 @@ public class VcsUtil { return VcsContextFactory.SERVICE.getInstance().createFilePathOnNonLocal(path, isDirectory); } - public static FilePath getFilePath(File file, boolean isDirectory) { + public static FilePath getFilePath(@NotNull File file, boolean isDirectory) { return VcsContextFactory.SERVICE.getInstance().createFilePathOn(file, isDirectory); } - public static FilePath getFilePathForDeletedFile(String path, boolean isDirectory) { + public static FilePath getFilePathForDeletedFile(@NotNull String path, boolean isDirectory) { return VcsContextFactory.SERVICE.getInstance().createFilePathOnDeleted(new File(path), isDirectory); } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/EquivalenceChecker.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/EquivalenceChecker.java index 75b455c8fcd0..a0e34a7170ca 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/EquivalenceChecker.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/EquivalenceChecker.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2015 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,34 +29,15 @@ public class EquivalenceChecker { private EquivalenceChecker() {} public static boolean statementsAreEquivalent(@Nullable PsiStatement statement1, @Nullable PsiStatement statement2) { + statement1 = ControlFlowUtils.stripBraces(statement1); + statement2 = ControlFlowUtils.stripBraces(statement2); if (statement1 == null) { return statement2 == null; } else if (statement2 == null) { return false; } if (statement1.getClass() != statement2.getClass()) { - if (statement1 instanceof PsiBlockStatement && !(statement2 instanceof PsiBlockStatement)) { - final PsiBlockStatement blockStatement = (PsiBlockStatement)statement1; - final PsiStatement[] statements = blockStatement.getCodeBlock().getStatements(); - if (statements.length != 1) { - return false; - } - statement1 = statements[0]; - } - else if (!(statement1 instanceof PsiBlockStatement) && statement2 instanceof PsiBlockStatement) { - final PsiBlockStatement blockStatement = (PsiBlockStatement)statement2; - final PsiStatement[] statements = blockStatement.getCodeBlock().getStatements(); - if (statements.length != 1) { - return false; - } - statement2 = statements[0]; - } - else { return false; - } - if (statement1.getClass() != statement2.getClass()) { - return false; - } } if (statement1 instanceof PsiAssertStatement) { return assertStatementsAreEquivalent((PsiAssertStatement)statement1, (PsiAssertStatement)statement2); @@ -698,8 +679,12 @@ public class EquivalenceChecker { if (classReference1 == null || classReference2 == null) { return false; } - final String text = classReference1.getText(); - if (!text.equals(classReference2.getText())) { + final PsiElement target1 = classReference1.resolve(); + if (target1 == null) { + return false; + } + final PsiElement target2 = classReference2.resolve(); + if (!target1.equals(target2)) { return false; } final PsiExpression[] arrayDimensions1 = diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/inheritance/redundant_method_override/RedundantMethodOverride.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/inheritance/redundant_method_override/RedundantMethodOverride.java index 797cab3c9f13..987d55568c9e 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/inheritance/redundant_method_override/RedundantMethodOverride.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/inheritance/redundant_method_override/RedundantMethodOverride.java @@ -28,4 +28,23 @@ class S { void m() { System.out.println(); } +} +class A { + void f() { + new X(); + } + + class X {} +} +class BB extends A { + void f() { + new X(); + } + + class X {} +} +class CC extends A { + void f() { + new X(); + } } \ No newline at end of file diff --git a/plugins/settings-repository/src/sync.kt b/plugins/settings-repository/src/sync.kt index 15d65183610a..51772d3cd4f2 100644 --- a/plugins/settings-repository/src/sync.kt +++ b/plugins/settings-repository/src/sync.kt @@ -15,11 +15,11 @@ */ package org.jetbrains.settingsRepository +import com.intellij.configurationStore.ComponentStoreImpl import com.intellij.configurationStore.SchemeManagerFactoryBase import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.WriteAction import com.intellij.openapi.application.impl.ApplicationImpl -import com.intellij.openapi.components.impl.stores.ComponentStoreImpl import com.intellij.openapi.components.impl.stores.FileBasedStorage import com.intellij.openapi.components.impl.stores.IComponentStore import com.intellij.openapi.components.impl.stores.StoreUtil diff --git a/resources/src/componentSets/IdeaComponents.xml b/resources/src/componentSets/IdeaComponents.xml index 919f5befbe42..028753cb3a35 100644 --- a/resources/src/componentSets/IdeaComponents.xml +++ b/resources/src/componentSets/IdeaComponents.xml @@ -16,7 +16,7 @@ com.intellij.openapi.project.impl.ProjectStoreClassProvider - com.intellij.openapi.components.impl.stores.PlatformLangProjectStoreClassProvider + com.intellij.configurationStore.PlatformLangProjectStoreClassProvider diff --git a/xml/tests/src/com/intellij/codeInsight/editorActions/EscapeEntitiesActionTest.java b/xml/tests/src/com/intellij/codeInsight/editorActions/EscapeEntitiesActionTest.java index edcc335d255e..9cd5a3cdb71b 100644 --- a/xml/tests/src/com/intellij/codeInsight/editorActions/EscapeEntitiesActionTest.java +++ b/xml/tests/src/com/intellij/codeInsight/editorActions/EscapeEntitiesActionTest.java @@ -15,12 +15,15 @@ */ package com.intellij.codeInsight.editorActions; +import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; /** * @author Dennis.Ushakov */ public class EscapeEntitiesActionTest extends LightCodeInsightFixtureTestCase { + private static final String NDASH = new String(new byte[]{-30, -128, -109}, CharsetToolkit.UTF8_CHARSET); + public void testSimpleHtml() { doTest("<<<", "html", "<<<"); } @@ -30,11 +33,11 @@ public class EscapeEntitiesActionTest extends LightCodeInsightFixtureTestCase { } public void testWide() { - doTest("\u2013", "html", "–"); + doTest(NDASH, "html", "–"); } public void testAttributeValue() { - doTest("", "html", ""); + doTest("", "html", ""); } public void testTag() {