diff options
Diffstat (limited to 'platform/platform-impl/src/com/intellij/openapi/components/impl')
19 files changed, 593 insertions, 619 deletions
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ApplicationStoreImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ApplicationStoreImpl.java index a00533d3244b..bf03cb11f1d6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ApplicationStoreImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ApplicationStoreImpl.java @@ -36,7 +36,6 @@ class ApplicationStoreImpl extends ComponentStoreImpl implements IApplicationSto private static final String XML_EXTENSION = ".xml"; private static final String DEFAULT_STORAGE_SPEC = StoragePathMacros.APP_CONFIG + "/" + PathManager.DEFAULT_OPTIONS_FILE_NAME + XML_EXTENSION; - private static final String OPTIONS_MACRO = "OPTIONS"; private static final String ROOT_ELEMENT_NAME = "application"; private final ApplicationImpl myApplication; @@ -93,14 +92,13 @@ class ApplicationStoreImpl extends ComponentStoreImpl implements IApplicationSto } @Override - public void setOptionsPath(final String path) { - myStateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.APP_CONFIG), path); - myStateStorageManager.addMacro(OPTIONS_MACRO, path); + public void setOptionsPath(@NotNull String path) { + myStateStorageManager.addMacro(StoragePathMacros.APP_CONFIG, path); } @Override public void setConfigPath(@NotNull final String configPath) { - myStateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.ROOT_CONFIG), configPath); + myStateStorageManager.addMacro(StoragePathMacros.ROOT_CONFIG, configPath); myConfigPath = configPath; } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/BaseFileConfigurableStoreImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/BaseFileConfigurableStoreImpl.java index 25dd8a05cab3..dc07fee151e2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/BaseFileConfigurableStoreImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/BaseFileConfigurableStoreImpl.java @@ -59,8 +59,8 @@ abstract class BaseFileConfigurableStoreImpl extends ComponentStoreImpl { } @Override - public void load(@NotNull final Element rootElement) throws IOException { - super.load(rootElement); + public void load(@NotNull Element rootElement, @Nullable PathMacroSubstitutor pathMacroSubstitutor, boolean intern) { + super.load(rootElement, pathMacroSubstitutor, intern); final String v = rootElement.getAttributeValue(VERSION_OPTION); if (v != null) { @@ -74,7 +74,11 @@ abstract class BaseFileConfigurableStoreImpl extends ComponentStoreImpl { @Override @NotNull protected Element save() { - final Element root = super.save(); + Element root = super.save(); + if (root == null) { + root = new Element(myRootElementName); + } + root.setAttribute(VERSION_OPTION, Integer.toString(myVersion)); return root; } @@ -113,7 +117,7 @@ abstract class BaseFileConfigurableStoreImpl extends ComponentStoreImpl { } public BaseStorageData getMainStorageData() throws StateStorageException { - return (BaseStorageData) getMainStorage().getStorageData(false); + return (BaseStorageData)getMainStorage().getStorageData(); } @Nullable diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java index fc2017b57a4a..ed63bf12d4c4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java @@ -29,12 +29,12 @@ import com.intellij.openapi.util.*; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; import com.intellij.util.ReflectionUtil; -import com.intellij.util.io.fs.IFile; import gnu.trove.THashMap; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.File; import java.io.IOException; import java.lang.reflect.Type; import java.util.*; @@ -46,12 +46,6 @@ public abstract class ComponentStoreImpl implements IComponentStore { private final List<SettingsSavingComponent> mySettingsSavingComponents = Collections.synchronizedList(new ArrayList<SettingsSavingComponent>()); @Nullable private SaveSessionImpl mySession; - @Deprecated - @Nullable - private StateStorage getStateStorage(@NotNull final Storage storageSpec) throws StateStorageException { - return getStateStorageManager().getStateStorage(storageSpec); - } - @Nullable protected abstract StateStorage getDefaultsStorage(); @@ -255,9 +249,10 @@ public abstract class ComponentStoreImpl implements IComponentStore { Storage[] storageSpecs = getComponentStorageSpecs(component, StateStorageOperation.READ); for (Storage storageSpec : storageSpecs) { - StateStorage stateStorage = getStateStorage(storageSpec); - if (stateStorage == null || !stateStorage.hasState(component, name, stateClass, reloadData)) continue; - state = stateStorage.getState(component, name, stateClass, state); + StateStorage stateStorage = getStateStorageManager().getStateStorage(storageSpec); + if (stateStorage != null && stateStorage.hasState(component, name, stateClass, reloadData)) { + state = stateStorage.getState(component, name, stateClass, state); + } } if (state != null) { @@ -320,17 +315,15 @@ public abstract class ComponentStoreImpl implements IComponentStore { } assert storages.length > 0; - final Class<StorageAnnotationsDefaultValues.NullStateStorageChooser> defaultClass = - StorageAnnotationsDefaultValues.NullStateStorageChooser.class; - final Class<? extends StateStorageChooser> storageChooserClass = stateSpec.storageChooser(); - final StateStorageChooser<PersistentStateComponent<?>> defaultStateStorageChooser = getDefaultStateStorageChooser(); - assert storageChooserClass != defaultClass || defaultStateStorageChooser != null : "State chooser not specified for: " + - persistentStateComponent.getClass(); - - if (storageChooserClass == defaultClass) { + if (storageChooserClass == StateStorageChooser.class) { + StateStorageChooser<PersistentStateComponent<?>> defaultStateStorageChooser = getDefaultStateStorageChooser(); + assert defaultStateStorageChooser != null : "State chooser not specified for: " + persistentStateComponent.getClass(); return defaultStateStorageChooser.selectStorages(storages, persistentStateComponent, operation); } + else if (storageChooserClass == LastStorageChooserForWrite.class) { + return LastStorageChooserForWrite.INSTANCE.selectStorages(storages, persistentStateComponent, operation); + } else { try { @SuppressWarnings("unchecked") @@ -361,7 +354,7 @@ public abstract class ComponentStoreImpl implements IComponentStore { @NotNull @Override - public List<IFile> getAllStorageFilesToSave(final boolean includingSubStructures) throws IOException { + public List<File> getAllStorageFilesToSave(final boolean includingSubStructures) throws IOException { try { return myStorageManagerSaveSession.getAllStorageFilesToSave(); } @@ -426,12 +419,10 @@ public abstract class ComponentStoreImpl implements IComponentStore { protected void commit() throws StateStorageException { final StateStorageManager storageManager = getStateStorageManager(); - final StateStorageManager.ExternalizationSession session = storageManager.startExternalization(); String[] names = ArrayUtil.toStringArray(myComponents.keySet()); Arrays.sort(names); - for (String name : names) { Object component = myComponents.get(name); if (component instanceof PersistentStateComponent) { @@ -452,10 +443,9 @@ public abstract class ComponentStoreImpl implements IComponentStore { @NotNull @Override - public List<IFile> getAllStorageFiles(final boolean includingSubStructures) { + public List<File> getAllStorageFiles(final boolean includingSubStructures) { return myStorageManagerSaveSession.getAllStorageFiles(); } - } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/CompoundSaveSession.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/CompoundSaveSession.java index 51cc717726f3..aacdb58aeeec 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/CompoundSaveSession.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/CompoundSaveSession.java @@ -18,9 +18,9 @@ package com.intellij.openapi.components.impl.stores; import com.intellij.openapi.components.StateStorage; import com.intellij.openapi.components.StateStorageException; import com.intellij.util.SmartList; -import com.intellij.util.io.fs.IFile; import gnu.trove.THashMap; +import java.io.File; import java.util.List; import java.util.Map; @@ -36,8 +36,8 @@ public class CompoundSaveSession { } } - public List<IFile> getAllStorageFilesToSave() throws StateStorageException { - List<IFile> result = new SmartList<IFile>(); + public List<File> getAllStorageFilesToSave() throws StateStorageException { + List<File> result = new SmartList<File>(); for (StateStorage.SaveSession saveSession : mySaveSessions.values()) { result.addAll(saveSession.getStorageFilesToSave()); } @@ -70,8 +70,8 @@ public class CompoundSaveSession { return mySaveSessions.get(storage); } - public List<IFile> getAllStorageFiles() { - List<IFile> result = new SmartList<IFile>(); + public List<File> getAllStorageFiles() { + List<File> result = new SmartList<File>(); for (StateStorage.SaveSession saveSession : mySaveSessions.values()) { result.addAll(saveSession.getAllStorageFiles()); } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultProjectStoreImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultProjectStoreImpl.java index 6f0c3b8122cf..fad17c8d2889 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultProjectStoreImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultProjectStoreImpl.java @@ -21,13 +21,12 @@ import com.intellij.openapi.project.impl.ProjectImpl; import com.intellij.openapi.project.impl.ProjectManagerImpl; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.io.fs.IFile; -import org.jdom.Document; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.Collections; @@ -40,10 +39,10 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl { private final ProjectManagerImpl myProjectManager; @NonNls private static final String ROOT_TAG_NAME = "defaultProject"; - public DefaultProjectStoreImpl(final ProjectImpl project, final ProjectManagerImpl projectManager) { + public DefaultProjectStoreImpl(@NotNull ProjectImpl project, final ProjectManagerImpl projectManager) { super(project); - myProjectManager = projectManager; + myProjectManager = projectManager; myElement = projectManager.getDefaultProjectRootElement(); } @@ -53,29 +52,28 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl { return element != null ? element.clone() : null; } - @NotNull @Override protected StateStorageManager createStateStorageManager() { - Document _d = null; + Element _d = null; if (myElement != null) { myElement.detach(); - _d = new Document(myElement); + _d = myElement; } final ComponentManager componentManager = getComponentManager(); final PathMacroManager pathMacroManager = PathMacroManager.getInstance(componentManager); - final Document document = _d; + final Element element = _d; - final XmlElementStorage storage = new XmlElementStorage(pathMacroManager.createTrackingSubstitutor(), componentManager, - ROOT_TAG_NAME, null, "", ComponentRoamingManager.getInstance(), + final XmlElementStorage storage = new XmlElementStorage("", RoamingType.DISABLED, pathMacroManager.createTrackingSubstitutor(), componentManager, + ROOT_TAG_NAME, null, ComponentVersionProvider.EMPTY) { @Override @Nullable - protected Document loadDocument() throws StateStorageException { - return document; + protected Element loadLocalData() { + return element; } @Override @@ -96,26 +94,28 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl { @Override protected void doSave() throws StateStorageException { - myProjectManager.setDefaultProjectRootElement(getDocumentToSave().getRootElement()); + Element element = getElementToSave(); + myProjectManager.setDefaultProjectRootElement(element == null ? null : element); } @NotNull @Override - public Collection<IFile> getStorageFilesToSave() throws StateStorageException { + public Collection<File> getStorageFilesToSave() throws StateStorageException { return Collections.emptyList(); } @NotNull @Override - public List<IFile> getAllStorageFiles() { + public List<File> getAllStorageFiles() { return Collections.emptyList(); } } }; + //noinspection deprecation return new StateStorageManager() { @Override - public void addMacro(String macro, String expansion) { + public void addMacro(@NotNull String macro, @NotNull String expansion) { throw new UnsupportedOperationException("Method addMacro not implemented in " + getClass()); } @@ -131,6 +131,12 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl { return storage; } + @Nullable + @Override + public StateStorage getStateStorage(@NotNull String fileSpec, @NotNull RoamingType roamingType) { + return storage; + } + @Override @Nullable public StateStorage getFileStateStorage(@NotNull String fileSpec) { @@ -158,6 +164,7 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl { storage.finishSave(((MySaveSession)saveSession).saveSession); } + @NotNull @Override public String expandMacros(@NotNull String file) { throw new UnsupportedOperationException("Method expandMacros not implemented in " + getClass()); @@ -186,6 +193,7 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl { throw new UnsupportedOperationException("Method getStreamProviders not implemented in " + getClass()); } + @NotNull @Override public Collection<String> getStorageFileNames() { throw new UnsupportedOperationException("Method getStorageFileNames not implemented in " + getClass()); @@ -238,13 +246,13 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl { @NotNull @Override - public List<IFile> getAllStorageFilesToSave() throws StateStorageException { + public List<File> getAllStorageFilesToSave() throws StateStorageException { return Collections.emptyList(); } @NotNull @Override - public List<IFile> getAllStorageFiles() { + public List<File> getAllStorageFiles() { return Collections.emptyList(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultsStateStorage.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultsStateStorage.java index b62db63b73c2..9415aee49b09 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultsStateStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultsStateStorage.java @@ -65,12 +65,12 @@ class DefaultsStateStorage implements StateStorage { } @Nullable - public <T> T getState(final Object component, final String componentName, final Class<T> stateClass, @Nullable final T mergeInto) throws + public <T> T getState(final Object component, @NotNull final String componentName, final Class<T> stateClass, @Nullable final T mergeInto) throws StateStorageException { return DefaultStateSerializer.deserializeState(getState(component, componentName), stateClass, mergeInto); } - public boolean hasState(final Object component, final String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException { + public boolean hasState(final Object component, @NotNull final String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException { final URL url = DecodeDefaultsUtil.getDefaults(component, componentName); return url != null; } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DirectoryBasedStorage.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DirectoryBasedStorage.java index cda453be5cd2..912c239cffcb 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DirectoryBasedStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DirectoryBasedStorage.java @@ -26,7 +26,8 @@ import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.*; import com.intellij.openapi.vfs.tracker.VirtualFileTracker; -import com.intellij.util.io.fs.IFile; +import com.intellij.util.SmartList; +import com.intellij.util.containers.SmartHashSet; import com.intellij.util.messages.MessageBus; import org.jdom.Element; import org.jetbrains.annotations.NotNull; @@ -37,16 +38,13 @@ import java.io.File; import java.io.IOException; import java.util.*; -import static com.intellij.util.io.fs.FileSystem.FILE_SYSTEM; - //todo: support missing plugins //todo: support storage data public class DirectoryBasedStorage implements StateStorage, Disposable { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.impl.stores.DirectoryBasedStorage"); - private static final IFile[] EMPTY_FILES = new IFile[0]; private final TrackingPathMacroSubstitutor myPathMacroSubstitutor; - private final IFile myDir; + private final File myDir; private final StateSplitter mySplitter; private final FileTypeManager myFileTypeManager; @@ -59,7 +57,7 @@ public class DirectoryBasedStorage implements StateStorage, Disposable { @NotNull Disposable parentDisposable, @NotNull PicoContainer picoContainer) { myPathMacroSubstitutor = pathMacroSubstitutor; - myDir = FILE_SYSTEM.createFile(dir); + myDir = new File(dir); mySplitter = splitter; Disposer.register(parentDisposable, this); @@ -96,7 +94,7 @@ public class DirectoryBasedStorage implements StateStorage, Disposable { @Override @Nullable - public <T> T getState(final Object component, final String componentName, Class<T> stateClass, @Nullable T mergeInto) + public <T> T getState(final Object component, @NotNull final String componentName, Class<T> stateClass, @Nullable T mergeInto) throws StateStorageException { if (myStorageData == null) myStorageData = loadState(); @@ -116,7 +114,7 @@ public class DirectoryBasedStorage implements StateStorage, Disposable { @Override - public boolean hasState(final Object component, final String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException { + public boolean hasState(final Object component, @NotNull String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException { if (!myDir.exists()) return false; if (reloadData) myStorageData = null; return true; @@ -180,32 +178,28 @@ public class DirectoryBasedStorage implements StateStorage, Disposable { @Override public void save() throws StateStorageException { assert mySession == this; - final Set<String> currentNames = new HashSet<String>(); - - IFile[] children = myDir.exists() ? myDir.listFiles() : EMPTY_FILES; - for (IFile child : children) { - final String fileName = child.getName(); - if (!myFileTypeManager.isFileIgnored(fileName) && StringUtil.endsWithIgnoreCase(fileName, ".xml")) { - currentNames.add(fileName); + final Set<String> currentNames = new SmartHashSet<String>(); + File[] children = myDir.listFiles(); + if (children != null) { + for (File child : children) { + final String fileName = child.getName(); + if (!myFileTypeManager.isFileIgnored(fileName) && StringUtil.endsWithIgnoreCase(fileName, ".xml")) { + currentNames.add(fileName); + } } } myStorageData.process(new DirectoryStorageData.StorageDataProcessor() { @Override - public void process(final String componentName, final IFile file, final Element element) { + public void process(final String componentName, final File file, final Element element) { currentNames.remove(file.getName()); if (myPathMacroSubstitutor != null) { myPathMacroSubstitutor.collapsePaths(element); } - if (file.getTimeStamp() <= myStorageData.getLastTimeStamp()) { - if (!myDir.exists()) { - myDir.createParentDirs(); - myDir.mkDir(); - } - - StorageUtil.save(file, element, MySaveSession.this); + if (file.lastModified() <= myStorageData.getLastTimeStamp()) { + StorageUtil.save(file, element, MySaveSession.this, false, null); myStorageData.updateLastTimestamp(file); } } @@ -217,15 +211,14 @@ public class DirectoryBasedStorage implements StateStorage, Disposable { public void run() { if (myDir.exists()) { for (String name : currentNames) { - IFile child = myDir.getChild(name); - - if (child.getTimeStamp() > myStorageData.getLastTimeStamp()) { + File child = new File(myDir, name); + if (child.lastModified() > myStorageData.getLastTimeStamp()) { // do not touch new files during VC update (which aren't read yet) // now got an opposite problem: file is recreated if was removed by VC during update. return; } - final VirtualFile virtualFile = StorageUtil.getVirtualFile(child); + final VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByIoFile(child); if (virtualFile != null) { try { LOG.debug("Removing configuration file: " + virtualFile.getPresentableUrl()); @@ -272,23 +265,26 @@ public class DirectoryBasedStorage implements StateStorage, Disposable { @Override @NotNull - public Collection<IFile> getStorageFilesToSave() throws StateStorageException { + public Collection<File> getStorageFilesToSave() throws StateStorageException { assert mySession == this; if (!myDir.exists()) return getAllStorageFiles(); assert myDir.isDirectory() : myDir.getPath(); - final List<IFile> filesToSave = new ArrayList<IFile>(); - - IFile[] children = myDir.listFiles(); - final Set<String> currentChildNames = new HashSet<String>(); - for (IFile child : children) { - if (!myFileTypeManager.isFileIgnored(child.getName())) currentChildNames.add(child.getName()); + final List<File> filesToSave = new ArrayList<File>(); + final Set<String> currentChildNames = new SmartHashSet<String>(); + File[] children = myDir.listFiles(); + if (children != null) { + for (File child : children) { + if (!myFileTypeManager.isFileIgnored(child.getName())) { + currentChildNames.add(child.getName()); + } + } } myStorageData.process(new DirectoryStorageData.StorageDataProcessor() { @Override - public void process(final String componentName, final IFile file, final Element element) { + public void process(final String componentName, final File file, final Element element) { if (currentChildNames.contains(file.getName())) { currentChildNames.remove(file.getName()); @@ -301,13 +297,11 @@ public class DirectoryBasedStorage implements StateStorage, Disposable { filesToSave.add(file); } } - } }); for (String childName : currentChildNames) { - final IFile child = myDir.getChild(childName); - filesToSave.add(child); + filesToSave.add(new File(myDir, childName)); } return filesToSave; @@ -315,8 +309,8 @@ public class DirectoryBasedStorage implements StateStorage, Disposable { @Override @NotNull - public List<IFile> getAllStorageFiles() { - return new ArrayList<IFile>(myStorageData.getAllStorageFiles().keySet()); + public List<File> getAllStorageFiles() { + return new SmartList<File>(myStorageData.getAllStorageFiles().keySet()); } } @@ -328,24 +322,25 @@ public class DirectoryBasedStorage implements StateStorage, Disposable { } @Override - public void setState(@NotNull final Object component, final String componentName, @NotNull final Object state, final Storage storageSpec) - throws StateStorageException { + public void setState(@NotNull final Object component, final String componentName, @NotNull final Object state, final Storage storageSpec) { assert mySession == this; setState(componentName, state, storageSpec); } - private void setState(final String componentName, @NotNull Object state, final Storage storageSpec) throws StateStorageException { + private void setState(final String componentName, @NotNull Object state, final Storage storageSpec) { try { final Element element = DefaultStateSerializer.serializeState(state, storageSpec); - for (Pair<Element, String> pair : mySplitter.splitState(element)) { - Element e = pair.first; - String name = pair.second; + if (element != null) { + for (Pair<Element, String> pair : mySplitter.splitState(element)) { + Element e = pair.first; + String name = pair.second; - Element statePart = new Element(StorageData.COMPONENT); - statePart.setAttribute(StorageData.NAME, componentName); - statePart.addContent(e.detach()); + Element statePart = new Element(StorageData.COMPONENT); + statePart.setAttribute(StorageData.NAME, componentName); + statePart.addContent(e.detach()); - myStorageData.put(componentName, myDir.getChild(name), statePart, false); + myStorageData.put(componentName, new File(myDir, name), statePart, false); + } } } catch (WriteExternalException e) { diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java index 923072d4fb1d..54fd9d65cb92 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java @@ -22,19 +22,14 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.PathManager; -import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.components.StateStorageException; -import com.intellij.openapi.components.StoragePathMacros; -import com.intellij.openapi.components.TrackingPathMacroSubstitutor; +import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.JDOMUtil; +import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.*; import com.intellij.openapi.vfs.tracker.VirtualFileTracker; -import com.intellij.util.io.fs.FileSystem; -import com.intellij.util.io.fs.IFile; import com.intellij.util.messages.MessageBus; -import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jetbrains.annotations.NonNls; @@ -44,46 +39,40 @@ import org.picocontainer.PicoContainer; import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.util.Collection; import java.util.Collections; import java.util.List; public class FileBasedStorage extends XmlElementStorage { - private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.impl.stores.FileBasedStorage"); + private static final Logger LOG = Logger.getInstance(FileBasedStorage.class); private static boolean ourConfigDirectoryRefreshed = false; private final String myFilePath; - private final IFile myFile; - private final String myRootElementName; + private final File myFile; private volatile VirtualFile myCachedVirtualFile; - public FileBasedStorage(@Nullable TrackingPathMacroSubstitutor pathMacroManager, - StreamProvider streamProvider, - String filePath, - String fileSpec, - String rootElementName, + public FileBasedStorage(@NotNull String filePath, + @NotNull String fileSpec, + @Nullable RoamingType roamingType, + @Nullable TrackingPathMacroSubstitutor pathMacroManager, + @NotNull String rootElementName, @NotNull Disposable parentDisposable, PicoContainer picoContainer, - ComponentRoamingManager componentRoamingManager, + @Nullable StreamProvider streamProvider, ComponentVersionProvider componentVersionProvider) { - super(pathMacroManager, parentDisposable, rootElementName, streamProvider, fileSpec, componentRoamingManager, componentVersionProvider); + super(fileSpec, roamingType, pathMacroManager, parentDisposable, rootElementName, streamProvider, componentVersionProvider); refreshConfigDirectoryOnce(); - myRootElementName = rootElementName; myFilePath = filePath; - myFile = FileSystem.FILE_SYSTEM.createFile(myFilePath); + myFile = new File(filePath); VirtualFileTracker virtualFileTracker = ServiceManager.getService(VirtualFileTracker.class); MessageBus messageBus = (MessageBus)picoContainer.getComponentInstanceOfType(MessageBus.class); if (virtualFileTracker != null && messageBus != null) { - final String path = myFile.getAbsolutePath(); - final String fileUrl = LocalFileSystem.PROTOCOL_PREFIX + path.replace(File.separatorChar, '/'); - final Listener listener = messageBus.syncPublisher(STORAGE_TOPIC); - virtualFileTracker.addTracker(fileUrl, new VirtualFileAdapter() { + virtualFileTracker.addTracker(LocalFileSystem.PROTOCOL_PREFIX + myFile.getAbsolutePath().replace(File.separatorChar, '/'), new VirtualFileAdapter() { @Override public void fileMoved(@NotNull VirtualFileMoveEvent event) { myCachedVirtualFile = null; @@ -95,6 +84,11 @@ public class FileBasedStorage extends XmlElementStorage { } @Override + public void fileCreated(@NotNull VirtualFileEvent event) { + myCachedVirtualFile = event.getFile(); + } + + @Override public void contentsChanged(@NotNull final VirtualFileEvent event) { if (!isDisposed()) { listener.storageFileChanged(event, FileBasedStorage.this); @@ -130,13 +124,6 @@ public class FileBasedStorage extends XmlElementStorage { return new FileSaveSession(externalizationSession); } - public void resetProviderCache() { - myProviderUpToDateHash = -1; - if (myRemoteVersionProvider != null) { - myRemoteVersionProvider.myProviderVersions = null; - } - } - private class FileSaveSession extends MySaveSession { protected FileSaveSession(MyExternalizationSession externalizationSession) { super(externalizationSession); @@ -145,9 +132,11 @@ public class FileBasedStorage extends XmlElementStorage { @Override protected boolean physicalContentNeedsSave() { VirtualFile file = getVirtualFile(); - if (file == null || !file.exists()) + if (file == null || !file.exists()) { return !myStorageData.isEmpty(); - return !StorageUtil.contentEquals(getDocumentToSave(), file); + } + Element element = getElementToSave(); + return element == null || !StorageUtil.contentEquals(element, file); } @Override @@ -169,14 +158,13 @@ public class FileBasedStorage extends XmlElementStorage { } LOG.assertTrue(myFile != null); - myCachedVirtualFile = StorageUtil.save(myFile, getDocumentToSave(), this); + myCachedVirtualFile = StorageUtil.save(myFile, getElementToSave(), this, true, myCachedVirtualFile); } @NotNull @Override - public Collection<IFile> getStorageFilesToSave() throws StateStorageException { - boolean needsSave = needsSave(); - if (needsSave) { + public Collection<File> getStorageFilesToSave() { + if (needsSave()) { if (LOG.isDebugEnabled()) { LOG.info("File " + myFileSpec + " needs save; hash=" + myUpToDateHash + "; currentHash=" + calcHash() + "; " + "content needs save=" + physicalContentNeedsSave()); @@ -190,21 +178,17 @@ public class FileBasedStorage extends XmlElementStorage { @NotNull @Override - public List<IFile> getAllStorageFiles() { + public List<File> getAllStorageFiles() { return Collections.singletonList(myFile); } } @Override - protected void loadState(final StorageData result, final Element element) throws StateStorageException { - ((FileStorageData)result).myFilePath = myFile.getAbsolutePath(); - super.loadState(result, element); - } - - @Override @NotNull protected StorageData createStorageData() { - return new FileStorageData(myRootElementName); + FileStorageData data = new FileStorageData(myRootElementName); + data.myFilePath = myFilePath; + return data; } public static class FileStorageData extends StorageData { @@ -234,18 +218,24 @@ public class FileBasedStorage extends XmlElementStorage { public VirtualFile getVirtualFile() { VirtualFile virtualFile = myCachedVirtualFile; if (virtualFile == null) { - myCachedVirtualFile = virtualFile = StorageUtil.getVirtualFile(myFile); + myCachedVirtualFile = virtualFile = LocalFileSystem.getInstance().findFileByIoFile(myFile); } return virtualFile; } + @NotNull public File getFile() { - return new File(myFile.getPath()); + return myFile; + } + + @NotNull + public String getFilePath() { + return myFilePath; } @Override @Nullable - protected Document loadDocument() throws StateStorageException { + protected Element loadLocalData() { myBlockSavingTheContent = false; try { VirtualFile file = getVirtualFile(); @@ -256,7 +246,7 @@ public class FileBasedStorage extends XmlElementStorage { if (file.getLength() == 0) { return processReadException(null); } - return loadDocumentImpl(file); + return StorageData.load(file); } catch (final JDOMException e) { return processReadException(e); @@ -267,7 +257,7 @@ public class FileBasedStorage extends XmlElementStorage { } @Nullable - private Document processReadException(@Nullable final Exception e) { + private Element processReadException(@Nullable final Exception e) { boolean contentTruncated = e == null; myBlockSavingTheContent = isProjectOrModuleOrWorkspaceFile() && !contentTruncated; if (!ApplicationManager.getApplication().isUnitTestMode() && !ApplicationManager.getApplication().isHeadlessEnvironment()) { @@ -291,45 +281,27 @@ public class FileBasedStorage extends XmlElementStorage { return isProjectOrModuleOrWorkspaceFile() && !contentTruncated ? "Please correct the file content" : "File content will be recreated"; } - private static Document loadDocumentImpl(final VirtualFile file) throws IOException, JDOMException { - InputStream stream = file.getInputStream(); - try { - return JDOMUtil.loadDocument(stream); - } - finally { - stream.close(); - } - } - - public String getFileName() { - return myFile.getName(); - } - - public String getFilePath() { - return myFilePath; - } - @Override public void setDefaultState(final Element element) { element.setName(myRootElementName); super.setDefaultState(element); } - protected boolean physicalContentNeedsSave(final Document doc) { - VirtualFile file = getVirtualFile(); - return file == null || !file.exists() || !StorageUtil.contentEquals(doc, file); - } - @Nullable public File updateFileExternallyFromStreamProviders() throws IOException { - StorageData loadedData = loadData(true); - Document document = getDocument(loadedData); - if (physicalContentNeedsSave(document)) { - File file = new File(myFile.getAbsolutePath()); - JDOMUtil.writeDocument(document, file, "\n"); - return file; + Element element = getElement(loadData(true)); + if (element == null) { + FileUtil.delete(myFile); + return null; } - return null; + BufferExposingByteArrayOutputStream out = StorageUtil.newContentIfDiffers(element, getVirtualFile()); + if (out == null) { + return null; + } + + File file = new File(myFile.getAbsolutePath()); + FileUtil.writeToFile(file, out.getInternalBuffer(), 0, out.size()); + return file; } } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IApplicationStore.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IApplicationStore.java index c669bd1f37be..0ebfae887771 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IApplicationStore.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IApplicationStore.java @@ -15,18 +15,18 @@ */ package com.intellij.openapi.components.impl.stores; -import com.intellij.openapi.components.StateStorageException; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.components.StateStorage; +import com.intellij.openapi.components.StateStorageException; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; -import java.util.Set; -import java.util.Collection; import java.io.IOException; +import java.util.Collection; +import java.util.Set; public interface IApplicationStore extends IComponentStore { - void setOptionsPath(String path); + void setOptionsPath(@NotNull String path); void setConfigPath(@NotNull String configPath); diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IComponentStore.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IComponentStore.java index 0427a8be15ab..93a65a2eb50b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IComponentStore.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IComponentStore.java @@ -19,10 +19,10 @@ import com.intellij.openapi.components.StateStorage; import com.intellij.openapi.components.StateStorageException; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.io.fs.IFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.File; import java.io.IOException; import java.util.List; import java.util.Set; @@ -54,17 +54,19 @@ public interface IComponentStore { interface SaveSession { @NotNull - List<IFile> getAllStorageFilesToSave(final boolean includingSubStructures) throws IOException; + List<File> getAllStorageFilesToSave(final boolean includingSubStructures) throws IOException; + @NotNull SaveSession save() throws IOException; + void finishSave(); + void reset(); @Nullable - Set<String> analyzeExternalChanges(@NotNull Set<Pair<VirtualFile,StateStorage>> changedFiles); + Set<String> analyzeExternalChanges(@NotNull Set<Pair<VirtualFile, StateStorage>> changedFiles); @NotNull - List<IFile> getAllStorageFiles(final boolean includingSubStructures); + List<File> getAllStorageFiles(final boolean includingSubStructures); } - } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/OldStreamProviderAdapter.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/OldStreamProviderAdapter.java index 2120030db2c1..ac7bf84f6b3e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/OldStreamProviderAdapter.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/OldStreamProviderAdapter.java @@ -12,6 +12,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +@SuppressWarnings("deprecation") final class OldStreamProviderAdapter extends StreamProvider implements CurrentUserHolder { final com.intellij.openapi.options.StreamProvider myProvider; private final RoamingType myRoamingType; @@ -32,9 +33,8 @@ final class OldStreamProviderAdapter extends StreamProvider implements CurrentUs } @Override - public boolean saveContent(@NotNull String fileSpec, @NotNull byte[] content, int size, @NotNull RoamingType roamingType, boolean async) throws IOException { + public void saveContent(@NotNull String fileSpec, @NotNull byte[] content, int size, @NotNull RoamingType roamingType, boolean async) throws IOException { myProvider.saveContent(fileSpec, new BufferExposingByteArrayInputStream(content, size), size, roamingType, async); - return false; } @Nullable @@ -65,4 +65,4 @@ final class OldStreamProviderAdapter extends StreamProvider implements CurrentUs public String getCurrentUserName() { return myProvider instanceof CurrentUserHolder ? ((CurrentUserHolder)myProvider).getCurrentUserName() : null; } -}
\ No newline at end of file +} diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStateStorageManager.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStateStorageManager.java index 0eed50a65131..c7b93afbe8d8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStateStorageManager.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStateStorageManager.java @@ -56,17 +56,12 @@ class ProjectStateStorageManager extends StateStorageManagerImpl { assert config != null : "Couldn't find old storage for " + component.getClass().getName(); final boolean workspace = isWorkspace(config.options); - String macro = StoragePathMacros.getMacroName(workspace ? StoragePathMacros.WORKSPACE_FILE : StoragePathMacros.PROJECT_FILE); - - String name = "$" + macro + "$"; - - StateStorage storage = getFileStateStorage(name); - + 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)) { - name = StoragePathMacros.PROJECT_FILE; + fileSpec = StoragePathMacros.PROJECT_FILE; } - - return name; + return fileSpec; } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStoreImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStoreImpl.java index 6288c62ab9e5..01e2f9e036d0 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStoreImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStoreImpl.java @@ -39,13 +39,14 @@ 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.OrderedSet; -import com.intellij.util.io.fs.FileSystem; -import com.intellij.util.io.fs.IFile; import org.jdom.Element; import org.jdom.JDOMException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.*; import java.lang.annotation.Annotation; @@ -55,23 +56,21 @@ import java.util.List; import java.util.Set; class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProjectStore { - private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.impl.stores.ProjectStoreImpl"); + private static final Logger LOG = Logger.getInstance(ProjectStoreImpl.class); @NonNls private static final String OLD_PROJECT_SUFFIX = "_old."; @NonNls static final String OPTION_WORKSPACE = "workspace"; - @NonNls static final String DEFAULT_STATE_STORAGE = StoragePathMacros.PROJECT_FILE; - static final Storage DEFAULT_STORAGE_ANNOTATION = new MyStorage(); private static int originalVersion = -1; protected ProjectImpl myProject; private StorageScheme myScheme = StorageScheme.DEFAULT; - private String myCachedLocation; private String myPresentableUrl; - ProjectStoreImpl(final ProjectImpl project) { + ProjectStoreImpl(@NotNull ProjectImpl project) { super(project); + myProject = project; } @@ -169,15 +168,15 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject final File dirStore = file.isDirectory() ? new File(file, Project.DIRECTORY_STORE_FOLDER) : new File(file.getParentFile(), Project.DIRECTORY_STORE_FOLDER); - stateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.PROJECT_FILE), new File(dirStore, "misc.xml").getPath()); + stateStorageManager.addMacro(StoragePathMacros.PROJECT_FILE, new File(dirStore, "misc.xml").getPath()); final File ws = new File(dirStore, "workspace.xml"); - stateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.WORKSPACE_FILE), ws.getPath()); + stateStorageManager.addMacro(StoragePathMacros.WORKSPACE_FILE, ws.getPath()); if (!ws.exists() && !file.isDirectory()) { useOldWsContent(filePath, ws); } - stateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.PROJECT_CONFIG_DIR), dirStore.getPath()); + stateStorageManager.addMacro(StoragePathMacros.PROJECT_CONFIG_DIR, dirStore.getPath()); ApplicationManager.getApplication().invokeAndWait(new Runnable() { @Override @@ -189,10 +188,10 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject else { myScheme = StorageScheme.DEFAULT; - stateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.PROJECT_FILE), filePath); + stateStorageManager.addMacro(StoragePathMacros.PROJECT_FILE, filePath); final String workspacePath = composeWsPath(filePath); - stateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.WORKSPACE_FILE), workspacePath); + stateStorageManager.addMacro(StoragePathMacros.WORKSPACE_FILE, workspacePath); ApplicationManager.getApplication().invokeAndWait(new Runnable() { @Override @@ -202,7 +201,6 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject }, ModalityState.defaultModalityState()); } - myCachedLocation = null; myPresentableUrl = null; } @@ -258,18 +256,26 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject final String path = getProjectFilePath(); if (!StringUtil.isEmptyOrSpaces(path)) { - return myScheme == StorageScheme.DEFAULT ? new File(path).getParent() : new File(path).getParentFile().getParent(); + return getBasePath(new File(path)); } //we are not yet initialized completely ("open directory", etc) - final StateStorage s = getStateStorageManager().getFileStateStorage(StoragePathMacros.PROJECT_FILE); - if (!(s instanceof FileBasedStorage)) return null; - final FileBasedStorage storage = (FileBasedStorage)s; + StateStorage storage = getStateStorageManager().getStateStorage(StoragePathMacros.PROJECT_FILE, RoamingType.PER_USER); + if (!(storage instanceof FileBasedStorage)) { + return null; + } - final File file = storage.getFile(); - if (file == null) return null; + return getBasePath(((FileBasedStorage)storage).getFile()); + } - return myScheme == StorageScheme.DEFAULT ? file.getParent() : file.getParentFile().getParent(); + 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 @@ -302,7 +308,7 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject return baseDir.getName().replace(":", ""); } else { - String temp = getProjectFileName(); + 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); @@ -316,13 +322,6 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject } @NotNull - private String getProjectFileName() { - final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getFileStateStorage(StoragePathMacros.PROJECT_FILE); - assert storage != null; - return storage.getFileName(); - } - - @NotNull @Override public StorageScheme getStorageScheme() { return myScheme; @@ -349,26 +348,28 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject @Override public VirtualFile getProjectFile() { - if (myProject.isDefault()) return null; - final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getFileStateStorage(StoragePathMacros.PROJECT_FILE); + return myProject.isDefault() ? null : ((FileBasedStorage)getProjectFileStorage()).getVirtualFile(); + } + + @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.getVirtualFile(); + return storage; } @Override public VirtualFile getWorkspaceFile() { if (myProject.isDefault()) return null; - final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getFileStateStorage(StoragePathMacros.WORKSPACE_FILE); + final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getStateStorage(StoragePathMacros.WORKSPACE_FILE, RoamingType.DISABLED); assert storage != null; return storage.getVirtualFile(); } @Override public void loadProjectFromTemplate(@NotNull final ProjectImpl defaultProject) { - final StateStorage stateStorage = getStateStorageManager().getFileStateStorage(DEFAULT_STATE_STORAGE); - - assert stateStorage instanceof XmlElementStorage; - XmlElementStorage xmlElementStorage = (XmlElementStorage)stateStorage; + XmlElementStorage stateStorage = getProjectFileStorage(); defaultProject.save(); final IProjectStore projectStore = defaultProject.getStateStore(); @@ -376,24 +377,19 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject DefaultProjectStoreImpl defaultProjectStore = (DefaultProjectStoreImpl)projectStore; final Element element = defaultProjectStore.getStateCopy(); if (element != null) { - xmlElementStorage.setDefaultState(element); + stateStorage.setDefaultState(element); } } @NotNull @Override public String getProjectFilePath() { - if (myProject.isDefault()) return ""; - final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getFileStateStorage(StoragePathMacros.PROJECT_FILE); - assert storage != null; - return storage.getFilePath(); + return myProject.isDefault() ? "" : ((FileBasedStorage)getProjectFileStorage()).getFilePath(); } @Override protected XmlElementStorage getMainStorage() { - final XmlElementStorage storage = (XmlElementStorage)getStateStorageManager().getFileStateStorage(DEFAULT_STATE_STORAGE); - assert storage != null; - return storage; + return getProjectFileStorage(); } @NotNull @@ -402,7 +398,6 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject return new ProjectStateStorageManager(PathMacroManager.getInstance(getComponentManager()).createTrackingSubstitutor(), myProject); } - static class ProjectStorageData extends BaseStorageData { protected final Project myProject; @@ -447,16 +442,16 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject } @Override - public void load(@NotNull final Element root) throws IOException { - final String v = root.getAttributeValue(VERSION_OPTION); + 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(root, originalVersion); + convert(rootElement, originalVersion); } - super.load(root); + super.load(rootElement, pathMacroSubstitutor, intern); } protected void convert(final Element root, final int originalVersion) { @@ -479,19 +474,16 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject @NotNull @Override - public List<IFile> getAllStorageFilesToSave(final boolean includingSubStructures) throws IOException { - List<IFile> result = new ArrayList<IFile>(); - + public List<File> getAllStorageFilesToSave(final boolean includingSubStructures) throws IOException { + List<File> result = new SmartList<File>(); if (includingSubStructures) { - collectSubfilesToSave(result); + collectSubFilesToSave(result); } - result.addAll(super.getAllStorageFilesToSave(false)); - return result; } - protected void collectSubfilesToSave(final List<IFile> result) throws IOException { } + protected void collectSubFilesToSave(final List<File> result) throws IOException { } @NotNull @Override @@ -523,10 +515,10 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject return ApplicationManager.getApplication().runReadAction(new Computable<ReadonlyStatusHandler.OperationStatus>() { @Override public ReadonlyStatusHandler.OperationStatus compute() { - final List<IFile> filesToSave; + final List<File> filesToSave; try { filesToSave = getAllStorageFilesToSave(true); - final Iterator<IFile> iterator = filesToSave.iterator(); + final Iterator<File> iterator = filesToSave.iterator(); while (iterator.hasNext()) { if (!iterator.next().exists()) { iterator.remove(); @@ -543,14 +535,12 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject if (myProject.isToSaveProjectName()) { final VirtualFile baseDir = getProjectBaseDir(); if (baseDir != null && baseDir.isValid()) { - filesToSave.add(FileSystem.FILE_SYSTEM - .createFile(new File(new File(baseDir.getPath(), Project.DIRECTORY_STORE_FOLDER), ProjectImpl.NAME_FILE).getPath())); + filesToSave.add(new File(new File(baseDir.getPath(), Project.DIRECTORY_STORE_FOLDER), ProjectImpl.NAME_FILE)); } } - for (IFile file : filesToSave) { + for (File file : filesToSave) { final VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByIoFile(file); - if (virtualFile != null) { virtualFile.refresh(false, false); if (virtualFile.isValid() && !virtualFile.isWritable()) { @@ -670,7 +660,7 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject @Override public String file() { - return DEFAULT_STATE_STORAGE; + return StoragePathMacros.PROJECT_FILE; } @Override @@ -679,15 +669,21 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject } @Override + public RoamingType roamingType() { + return RoamingType.PER_USER; + } + + @Override public Class<? extends StateStorage> storageClass() { - return StorageAnnotationsDefaultValues.NullStateStorage.class; + return StateStorage.class; } @Override public Class<? extends StateSplitter> stateSplitter() { - return StorageAnnotationsDefaultValues.NullStateSplitter.class; + return StateSplitter.class; } + @NotNull @Override public Class<? extends Annotation> annotationType() { throw new UnsupportedOperationException("Method annotationType not implemented in " + getClass()); diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/RoamingTypeExtensionPointBean.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/RoamingTypeExtensionPointBean.java deleted file mode 100644 index ff5d16361228..000000000000 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/RoamingTypeExtensionPointBean.java +++ /dev/null @@ -1,29 +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.util.xmlb.annotations.Attribute; - -/** - * @deprecated use {@link com.intellij.openapi.components.RoamingType#DISABLED} - */ -@Deprecated -public class RoamingTypeExtensionPointBean { - @Attribute("component") - public String componentName; - @Attribute("type") - public String roamingType; -} diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManager.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManager.java index 68d882d2b204..d3e9d1c03d2e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManager.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManager.java @@ -19,10 +19,10 @@ import com.intellij.openapi.components.*; import com.intellij.openapi.options.StreamProvider; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.io.fs.IFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.File; import java.util.Collection; import java.util.List; import java.util.Set; @@ -31,7 +31,7 @@ import java.util.Set; * @author mike */ public interface StateStorageManager { - void addMacro(String macro, String expansion); + void addMacro(@NotNull String macro, @NotNull String expansion); @Nullable TrackingPathMacroSubstitutor getMacroSubstitutor(); @@ -40,8 +40,16 @@ public interface StateStorageManager { StateStorage getStateStorage(@NotNull Storage storageSpec) throws StateStorageException; @Nullable + StateStorage getStateStorage(@NotNull String fileSpec, @NotNull RoamingType roamingType); + + @Deprecated + @Nullable + /** + * @deprecated Use {@link #getStateStorage(String, com.intellij.openapi.components.RoamingType)} + */ StateStorage getFileStateStorage(@NotNull String fileSpec); + @NotNull Collection<String> getStorageFileNames(); void clearStateStorage(@NotNull String file); @@ -57,7 +65,7 @@ public interface StateStorageManager { @Nullable StateStorage getOldStorage(Object component, String componentName, StateStorageOperation operation) throws StateStorageException; - @Nullable + @NotNull String expandMacros(@NotNull String file); @Deprecated @@ -81,11 +89,11 @@ public interface StateStorageManager { Set<String> analyzeExternalChanges(@NotNull Set<Pair<VirtualFile, StateStorage>> files); @NotNull - List<IFile> getAllStorageFilesToSave() throws StateStorageException; + List<File> getAllStorageFilesToSave() throws StateStorageException; @NotNull - List<IFile> getAllStorageFiles(); + List<File> getAllStorageFiles(); void save() throws StateStorageException; } -}
\ No newline at end of file +} diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java index 431c9a97820c..651acce271c0 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java @@ -24,12 +24,14 @@ import com.intellij.openapi.options.CurrentUserHolder; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.RoamingTypeDisabled; import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ObjectUtils; +import com.intellij.util.PathUtilRt; +import com.intellij.util.ReflectionUtil; import com.intellij.util.SmartList; -import com.intellij.util.io.fs.IFile; import gnu.trove.THashMap; import gnu.trove.THashSet; import gnu.trove.TObjectLongHashMap; @@ -99,9 +101,14 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di } @Override - public synchronized void addMacro(String macro, String expansion) { - // avoid hundreds of $MODULE_FILE$ instances - myMacros.put(("$" + macro + "$").intern(), expansion); + 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); } @Override @@ -123,15 +130,15 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di } } - @Override @Nullable - public StateStorage getFileStateStorage(@NotNull String fileName) { + @Override + public StateStorage getStateStorage(@NotNull String fileSpec, @NotNull RoamingType roamingType) { myStorageLock.lock(); try { - StateStorage stateStorage = myStorages.get(fileName); + StateStorage stateStorage = myStorages.get(fileSpec); if (stateStorage == null) { - stateStorage = createFileStateStorage(fileName); - putStorageToMap(fileName, stateStorage); + stateStorage = createFileStateStorage(fileSpec, roamingType); + putStorageToMap(fileSpec, stateStorage); } return stateStorage; } @@ -141,6 +148,13 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di } @Override + @Nullable + public StateStorage getFileStateStorage(@NotNull String fileSpec) { + return getStateStorage(fileSpec, RoamingType.PER_USER); + } + + @NotNull + @Override public Collection<String> getStorageFileNames() { myStorageLock.lock(); try { @@ -176,19 +190,19 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di @Nullable private StateStorage createStateStorage(Storage storageSpec) throws StateStorageException { - if (!storageSpec.storageClass().equals(StorageAnnotationsDefaultValues.NullStateStorage.class)) { + if (!storageSpec.storageClass().equals(StateStorage.class)) { String key = UUID.randomUUID().toString(); ((MutablePicoContainer)myPicoContainer).registerComponentImplementation(key, storageSpec.storageClass()); return (StateStorage)myPicoContainer.getComponentInstance(key); } - if (!storageSpec.stateSplitter().equals(StorageAnnotationsDefaultValues.NullStateSplitter.class)) { + if (!storageSpec.stateSplitter().equals(StateSplitter.class)) { return createDirectoryStateStorage(storageSpec.file(), storageSpec.stateSplitter()); } - return createFileStateStorage(storageSpec.file()); + return createFileStateStorage(storageSpec.file(), storageSpec.roamingType()); } private static String getStorageSpecId(Storage storageSpec) { - if (!storageSpec.storageClass().equals(StorageAnnotationsDefaultValues.NullStateStorage.class)) { + if (!storageSpec.storageClass().equals(StateStorage.class)) { return storageSpec.storageClass().getName(); } else { @@ -209,41 +223,30 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di @Nullable private StateStorage createDirectoryStateStorage(String file, Class<? extends StateSplitter> splitterClass) throws StateStorageException { - String expandedFile = expandMacros(file); - if (expandedFile == null) { - myStorages.put(file, null); - return null; - } - final StateSplitter splitter; try { - splitter = splitterClass.newInstance(); + splitter = ReflectionUtil.newInstance(splitterClass); } - catch (InstantiationException e) { + catch (RuntimeException e) { throw new StateStorageException(e); } - catch (IllegalAccessException e) { - throw new StateStorageException(e); - } - - return new DirectoryBasedStorage(myPathMacroSubstitutor, expandedFile, splitter, this, myPicoContainer); + return new DirectoryBasedStorage(myPathMacroSubstitutor, expandMacros(file), splitter, this, myPicoContainer); } @Nullable - private StateStorage createFileStateStorage(@NotNull final String fileSpec) { + private StateStorage createFileStateStorage(@NotNull final String fileSpec, @Nullable RoamingType roamingType) { String expandedFile = expandMacros(fileSpec); - if (expandedFile == null) { - myStorages.put(fileSpec, null); - return null; - } - String extension = FileUtilRt.getExtension(new File(expandedFile).getName()); - if (!ourHeadlessEnvironment && extension.isEmpty()) { + if (!ourHeadlessEnvironment && PathUtilRt.getFileName(expandedFile).lastIndexOf('.') < 0) { throw new IllegalArgumentException("Extension is missing for storage file: " + expandedFile); } - return new FileBasedStorage(getMacroSubstitutor(fileSpec), getStreamProvider(), expandedFile, fileSpec, myRootTagName, this, - myPicoContainer, ComponentRoamingManager.getInstance(), this) { + if (roamingType != RoamingType.PER_USER && fileSpec.equals(StoragePathMacros.WORKSPACE_FILE)) { + roamingType = RoamingType.DISABLED; + } + + return new FileBasedStorage(expandedFile, fileSpec, roamingType, getMacroSubstitutor(fileSpec), myRootTagName, this, + myPicoContainer, getStreamProvider(), this) { @Override @NotNull protected StorageData createStorageData() { @@ -271,8 +274,7 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di String filePath = getNotNullVersionsFilePath(); if (filePath != null) { try { - Document document = JDOMUtil.loadDocument(new File(filePath)); - loadComponentVersions(result, document); + loadComponentVersions(result, JDOMUtil.loadDocument(new File(filePath))); } catch (JDOMException e) { LOG.debug(e); @@ -294,6 +296,7 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di public static void loadComponentVersions(TObjectLongHashMap<String> result, Document document) { List<Element> componentObjects = document.getRootElement().getChildren("component"); + result.ensureCapacity(componentObjects.size()); for (Element component : componentObjects) { String name = component.getAttributeValue("name"); String version = component.getAttributeValue("version"); @@ -330,26 +333,21 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di private static final Pattern MACRO_PATTERN = Pattern.compile("(\\$[^\\$]*\\$)"); @Override - @Nullable + @NotNull public synchronized String expandMacros(@NotNull String file) { - final Matcher matcher = MACRO_PATTERN.matcher(file); + Matcher matcher = MACRO_PATTERN.matcher(file); while (matcher.find()) { String m = matcher.group(1); - if (!myMacros.containsKey(m) || !ApplicationManager.getApplication().isUnitTestMode() && myMacros.get(m) == null) { - throw new IllegalArgumentException("Unknown macro: " + m + " in storage spec: " + file); + if (!myMacros.containsKey(m)) { + throw new IllegalArgumentException("Unknown macro: " + m + " in storage file spec: " + file); } } - String actualFile = file; - + String expanded = file; for (String macro : myMacros.keySet()) { - final String replacement = myMacros.get(macro); - if (replacement != null) { - actualFile = StringUtil.replace(actualFile, macro, replacement); - } + expanded = StringUtil.replace(expanded, macro, myMacros.get(macro)); } - - return actualFile; + return expanded; } @NotNull @@ -424,7 +422,9 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di @Override @Nullable public StateStorage getOldStorage(Object component, String componentName, StateStorageOperation operation) throws StateStorageException { - return getFileStateStorage(getOldStorageSpec(component, componentName, operation)); + String oldStorageSpec = getOldStorageSpec(component, componentName, operation); + //noinspection deprecation + return oldStorageSpec == null ? null : getStateStorage(oldStorageSpec, component instanceof RoamingTypeDisabled ? RoamingType.DISABLED : RoamingType.PER_USER); } @Nullable @@ -440,14 +440,14 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di @Override @NotNull - public List<IFile> getAllStorageFilesToSave() throws StateStorageException { + public List<File> getAllStorageFilesToSave() throws StateStorageException { assert mySession == this; return myCompoundSaveSession.getAllStorageFilesToSave(); } @Override @NotNull - public List<IFile> getAllStorageFiles() { + public List<File> getAllStorageFiles() { return myCompoundSaveSession.getAllStorageFiles(); } @@ -503,15 +503,16 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di } public void save() { - if (!isDirty) return; + if (!isDirty) { + return; + } + String filePath = getNotNullVersionsFilePath(); if (filePath != null) { - File dir = new File(filePath).getParentFile(); - if (!dir.isDirectory() && !dir.mkdirs()) { - LOG.warn("Unable to create: " + dir); - } + File file = new File(filePath); + FileUtilRt.createParentDirs(file); try { - JDOMUtil.writeDocument(new Document(createComponentVersionsXml(getComponentVersions())), filePath, "\n"); + JDOMUtil.writeParent(createComponentVersionsXml(getComponentVersions()), file, "\n"); isDirty = false; } catch (IOException e) { @@ -546,6 +547,7 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di return root; } + @SuppressWarnings("deprecation") private static class OldStreamProviderManager extends StreamProvider implements CurrentUserHolder { private final List<OldStreamProviderAdapter> myStreamProviders = new SmartList<OldStreamProviderAdapter>(); @@ -575,22 +577,17 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di } @Override - public boolean saveContent(@NotNull String fileSpec, @NotNull byte[] content, int size, @NotNull RoamingType roamingType, boolean async) throws IOException { - boolean result = false; + public void saveContent(@NotNull String fileSpec, @NotNull byte[] content, int size, @NotNull RoamingType roamingType, boolean async) throws IOException { for (StreamProvider streamProvider : myStreamProviders) { try { - if (streamProvider.isEnabled() && streamProvider.isApplicable(fileSpec, roamingType) && streamProvider.saveContent(fileSpec, content, size, roamingType, async)) { - result = true; + if (streamProvider.isEnabled() && streamProvider.isApplicable(fileSpec, roamingType)) { + streamProvider.saveContent(fileSpec, content, size, roamingType, async); } } - catch (ConnectException e) { - LOG.debug("Cannot send user profile to server: " + e.getLocalizedMessage()); - } catch (Exception e) { LOG.debug(e); } } - return result; } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StorageUtil.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StorageUtil.java index bd732705446a..2344c8526b0a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StorageUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StorageUtil.java @@ -26,7 +26,6 @@ import com.intellij.openapi.editor.DocumentRunnable; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.project.ex.ProjectEx; -import com.intellij.openapi.util.Couple; import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream; @@ -38,7 +37,6 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.SystemProperties; import com.intellij.util.UniqueFileNamesProvider; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.io.fs.IFile; import com.intellij.util.ui.UIUtil; import org.jdom.Document; import org.jdom.Element; @@ -59,11 +57,12 @@ import java.util.Set; * @author mike */ public class StorageUtil { - private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.impl.stores.StorageUtil"); + private static final Logger LOG = Logger.getInstance(StorageUtil.class); private static final boolean DUMP_COMPONENT_STATES = SystemProperties.getBooleanProperty("idea.log.externally.changed.component.states", false); @SuppressWarnings("SpellCheckingInspection") private static final SimpleDateFormat LOG_DIR_FORMAT = new SimpleDateFormat("yyyyMMdd-HHmmss"); + private static final Pair<byte[], String> NON_EXISTENT_FILE_DATA = Pair.create(null, SystemProperties.getLineSeparator()); private StorageUtil() { } @@ -110,34 +109,86 @@ public class StorageUtil { return notified; } + + public static boolean isEmpty(@Nullable Parent element) { + if (element == null) { + return true; + } + else if (element instanceof Element) { + return JDOMUtil.isEmpty((Element)element); + } + else { + Document document = (Document)element; + return !document.hasRootElement() || JDOMUtil.isEmpty(document.getRootElement()); + } + } + + /** + * Due to historical reasons files in ROOT_CONFIG don’t wrapped into document (xml prolog) opposite to files in APP_CONFIG + */ @Nullable - static VirtualFile save(@NotNull IFile file, Parent element, Object requestor) throws StateStorageException { - try { - String lineSeparator; - String oldText; - if (file.exists()) { - VirtualFile vFile = LocalFileSystem.getInstance().findFileByIoFile(file); - Couple<String> pair = loadFile(vFile); - lineSeparator = pair.second; - oldText = pair.first; + static VirtualFile save(@NotNull File file, @Nullable Parent element, Object requestor, boolean wrapAsDocument, @Nullable VirtualFile cachedVirtualFile) throws StateStorageException { + if (isEmpty(element)) { + if (!file.exists()) { + return null; + } + + VirtualFile virtualFile = cachedVirtualFile; + if (virtualFile == null || !virtualFile.isValid()) { + virtualFile = LocalFileSystem.getInstance().findFileByIoFile(file); + } + if (virtualFile == null) { + LOG.info("Cannot find virtual file " + file.getAbsolutePath()); + FileUtil.delete(file); } else { - oldText = null; - lineSeparator = SystemProperties.getLineSeparator(); - file.createParentDirs(); + AccessToken token = ApplicationManager.getApplication().acquireWriteActionLock(DocumentRunnable.IgnoreDocumentRunnable.class); + try { + virtualFile.delete(requestor); + } + catch (IOException e) { + throw new StateStorageException(e); + } + finally { + token.finish(); + } } + return null; + } - String text = JDOMUtil.writeParent(element, lineSeparator); - if (text.equals(oldText)) { - return null; + VirtualFile virtualFile = cachedVirtualFile == null || !cachedVirtualFile.isValid() ? null : cachedVirtualFile; + Parent document = !wrapAsDocument || element instanceof Document ? element : new Document((Element)element); + try { + BufferExposingByteArrayOutputStream byteOut; + if (file.exists()) { + if (virtualFile == null) { + virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file); + } + + Pair<byte[], String> pair = loadFile(virtualFile); + byteOut = writeToBytes(document, pair.second); + if (equal(pair.first, byteOut)) { + return null; + } + } + else { + FileUtil.createParentDirs(file); + byteOut = writeToBytes(document, SystemProperties.getLineSeparator()); } // mark this action as modifying the file which daemon analyzer should ignore AccessToken token = ApplicationManager.getApplication().acquireWriteActionLock(DocumentRunnable.IgnoreDocumentRunnable.class); try { - VirtualFile virtualFile = getOrCreateVirtualFile(requestor, file); - byte[] bytes = text.getBytes(CharsetToolkit.UTF8); - virtualFile.setBinaryContent(bytes, -1, -1, requestor); + if (virtualFile == null) { + virtualFile = getOrCreateVirtualFile(requestor, file); + } + OutputStream virtualFileOut = virtualFile.getOutputStream(requestor); + try { + byteOut.writeTo(virtualFileOut); + } + finally { + virtualFileOut.close(); + } return virtualFile; } finally { @@ -150,70 +201,78 @@ public class StorageUtil { } @NotNull - static VirtualFile getOrCreateVirtualFile(final Object requestor, final IFile ioFile) throws IOException { - VirtualFile vFile = getVirtualFile(ioFile); - - if (vFile == null) { - vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(ioFile); - } + private static BufferExposingByteArrayOutputStream writeToBytes(@NotNull Parent element, @NotNull String lineSeparator) throws IOException { + BufferExposingByteArrayOutputStream out = new BufferExposingByteArrayOutputStream(512); + JDOMUtil.writeParent(element, out, lineSeparator); + return out; + } - if (vFile == null) { - final IFile parentFile = ioFile.getParentFile(); - final VirtualFile parentVFile = - LocalFileSystem.getInstance().refreshAndFindFileByIoFile(parentFile); // need refresh if the directory has just been created - if (parentVFile == null) { - throw new IOException(ProjectBundle.message("project.configuration.save.file.not.found", parentFile.getPath())); + @NotNull + static VirtualFile getOrCreateVirtualFile(@Nullable Object requestor, @NotNull File ioFile) throws IOException { + VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(ioFile); + if (virtualFile == null) { + File parentFile = ioFile.getParentFile(); + // need refresh if the directory has just been created + VirtualFile parentVirtualFile = parentFile == null ? null : LocalFileSystem.getInstance().refreshAndFindFileByIoFile(parentFile); + if (parentVirtualFile == null) { + throw new IOException(ProjectBundle.message("project.configuration.save.file.not.found", parentFile == null ? "" : parentFile.getPath())); } - vFile = parentVFile.createChildData(requestor, ioFile.getName()); + virtualFile = parentVirtualFile.createChildData(requestor, ioFile.getName()); } - - return vFile; - } - - @Nullable - static VirtualFile getVirtualFile(final IFile ioFile) { - return LocalFileSystem.getInstance().findFileByIoFile(ioFile); + return virtualFile; } /** * @return pair.first - file contents (null if file does not exist), pair.second - file line separators */ - private static Couple<String> loadFile(@Nullable final VirtualFile file) throws IOException { + @NotNull + private static Pair<byte[], String> loadFile(@Nullable final VirtualFile file) throws IOException { if (file == null || !file.exists()) { - return Couple.of(null, SystemProperties.getLineSeparator()); + return NON_EXISTENT_FILE_DATA; } - String fileText = new String(file.contentsToByteArray(), CharsetToolkit.UTF8); - final int index = fileText.indexOf('\n'); - return Couple.of(fileText, index == -1 - ? SystemProperties.getLineSeparator() - : index - 1 >= 0 ? fileText.charAt(index - 1) == '\r' ? "\r\n" : "\n" : "\n"); + byte[] bytes = file.contentsToByteArray(); + String lineSeparator = file.getDetectedLineSeparator(); + if (lineSeparator == null) { + String fileText = new String(bytes, CharsetToolkit.UTF8); + final int index = fileText.indexOf('\n'); + lineSeparator = index == -1 + ? SystemProperties.getLineSeparator() + : index - 1 >= 0 ? fileText.charAt(index - 1) == '\r' ? "\r\n" : "\n" : "\n"; + } + return Pair.create(bytes, lineSeparator); } - public static boolean contentEquals(@NotNull final Document document, @NotNull final VirtualFile file) { + public static boolean contentEquals(@NotNull Parent element, @NotNull VirtualFile file) { + return newContentIfDiffers(element, file) == null; + } + + @Nullable + public static BufferExposingByteArrayOutputStream newContentIfDiffers(@NotNull Parent element, @Nullable VirtualFile file) { try { - final Couple<String> pair = loadFile(file); - return pair.first != null && pair.first.equals(JDOMUtil.writeDocument(document, pair.second)); + Pair<byte[], String> pair = loadFile(file); + BufferExposingByteArrayOutputStream out = writeToBytes(element, pair.second); + return pair.first != null && equal(pair.first, out) ? null : out; } catch (IOException e) { LOG.debug(e); - return false; + return null; } } - public static boolean contentEquals(@NotNull final Element element, @NotNull final VirtualFile file) { - try { - final Couple<String> pair = loadFile(file); - return pair.first != null && pair.first.equals(printElement(element, pair.second)); - } - catch (IOException e) { - LOG.debug(e); + public static boolean equal(byte[] a1, @NotNull BufferExposingByteArrayOutputStream out) { + int length = out.size(); + if (a1.length != length) { return false; } - } - static String printElement(final Element element, final String lineSeparator) throws StateStorageException { - return JDOMUtil.writeElement(element, lineSeparator); + byte[] internalBuffer = out.getInternalBuffer(); + for (int i = 0; i < length; i++) { + if (a1[i] != internalBuffer[i]) { + return false; + } + } + return true; } @Nullable @@ -229,6 +288,7 @@ public class StorageUtil { } } + @SuppressWarnings("Contract") @Nullable public static Document loadDocument(@Nullable InputStream stream) { if (stream == null) { @@ -252,29 +312,20 @@ public class StorageUtil { } @NotNull - public static BufferExposingByteArrayOutputStream documentToBytes(@NotNull Document document, boolean useSystemLineSeparator) throws IOException { - BufferExposingByteArrayOutputStream out = new BufferExposingByteArrayOutputStream(512); - OutputStreamWriter writer = new OutputStreamWriter(out, CharsetToolkit.UTF8_CHARSET); - try { - JDOMUtil.writeDocument(document, writer, useSystemLineSeparator ? SystemProperties.getLineSeparator() : "\n"); - return out; - } - finally { - writer.close(); - } + public static BufferExposingByteArrayOutputStream elementToBytes(@NotNull Parent element, boolean useSystemLineSeparator) throws IOException { + return writeToBytes(element, useSystemLineSeparator ? SystemProperties.getLineSeparator() : "\n"); } - public static boolean sendContent(@NotNull StreamProvider provider, @NotNull String fileSpec, @NotNull Document copy, @NotNull RoamingType type, boolean async) { + public static void sendContent(@NotNull StreamProvider provider, @NotNull String fileSpec, @NotNull Parent element, @NotNull RoamingType type, boolean async) { if (!provider.isApplicable(fileSpec, type)) { - return false; + return; } try { - return doSendContent(provider, fileSpec, copy, type, async); + doSendContent(provider, fileSpec, element, type, async); } catch (IOException e) { LOG.warn(e); - return false; } } @@ -287,10 +338,10 @@ public class StorageUtil { /** * You must call {@link StreamProvider#isApplicable(String, com.intellij.openapi.components.RoamingType)} before */ - public static boolean doSendContent(StreamProvider provider, String fileSpec, Document copy, RoamingType type, boolean async) throws IOException { + public static void doSendContent(@NotNull StreamProvider provider, @NotNull String fileSpec, @NotNull Parent element, @NotNull RoamingType type, boolean async) throws IOException { // we should use standard line-separator (\n) - stream provider can share file content on any OS - BufferExposingByteArrayOutputStream content = documentToBytes(copy, false); - return provider.saveContent(fileSpec, content.getInternalBuffer(), content.size(), type, async); + BufferExposingByteArrayOutputStream content = elementToBytes(element, false); + provider.saveContent(fileSpec, content.getInternalBuffer(), content.size(), type, async); } public static void logStateDiffInfo(Set<Pair<VirtualFile, StateStorage>> changedFiles, Set<String> componentNames) { @@ -309,10 +360,9 @@ public class StorageUtil { StateStorage storage = pair.second; if (storage instanceof XmlElementStorage) { - Document state = ((XmlElementStorage)storage).logComponents(); + Element state = ((XmlElementStorage)storage).logComponents(); if (state != null) { - File logFile = new File(logDirectory, "prev_" + file.getName()); - JDOMUtil.writeDocument(state, logFile, "\n"); + JDOMUtil.writeParent(state, new File(logDirectory, "prev_" + file.getName()), "\n"); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StreamProvider.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StreamProvider.java index ec57d8c63601..cf49b927ad0e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StreamProvider.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StreamProvider.java @@ -12,7 +12,9 @@ import java.util.Collections; public abstract class StreamProvider { public static final StreamProvider[] EMPTY_ARRAY = new StreamProvider[0]; - public abstract boolean isEnabled(); + public boolean isEnabled() { + return true; + } /** * If true, special version file per storage file will keep version of component. @@ -37,7 +39,7 @@ public abstract class StreamProvider { * @param roamingType * @param async */ - public abstract boolean saveContent(@NotNull String fileSpec, @NotNull byte[] content, int size, @NotNull RoamingType roamingType, boolean async) throws IOException; + public abstract void saveContent(@NotNull String fileSpec, @NotNull byte[] content, int size, @NotNull RoamingType roamingType, boolean async) throws IOException; @Nullable public abstract InputStream loadContent(@NotNull String fileSpec, @NotNull RoamingType roamingType) throws IOException; diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java index b028676168d5..76f47db77533 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java @@ -15,44 +15,48 @@ */ package com.intellij.openapi.components.impl.stores; -import com.intellij.ide.plugins.IdeaPluginDescriptorImpl; import com.intellij.openapi.Disposable; import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.options.CurrentUserHolder; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.vfs.SafeWriteRequestor; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.io.fs.IFile; import gnu.trove.THashMap; +import gnu.trove.THashSet; import gnu.trove.TObjectLongHashMap; import org.jdom.Document; import org.jdom.Element; +import org.jdom.JDOMException; import org.jdom.filter.ElementFilter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.util.*; public abstract class XmlElementStorage implements StateStorage, Disposable { - private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.impl.stores.XmlElementStorage"); + private static final Logger LOG = Logger.getInstance(XmlElementStorage.class); + + private final static RoamingElementFilter DISABLED_ROAMING_ELEMENT_FILTER = new RoamingElementFilter(RoamingType.DISABLED); private static final String ATTR_NAME = "name"; private static final String VERSION_FILE_SUFFIX = ".ver"; protected TrackingPathMacroSubstitutor myPathMacroSubstitutor; - @NotNull private final String myRootElementName; + @NotNull protected final String myRootElementName; private Object mySession; private StorageData myLoadedData; protected final StreamProvider myStreamProvider; protected final String myFileSpec; - private final ComponentRoamingManager myComponentRoamingManager; protected boolean myBlockSavingTheContent = false; protected int myUpToDateHash = -1; - protected int myProviderUpToDateHash = -1; + private int myProviderUpToDateHash = -1; private boolean mySavingDisabled = false; private final Map<String, Object> myStorageComponentStates = new THashMap<String, Object>(); // at load we store Element, on setState Integer of hash @@ -60,6 +64,8 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { private final ComponentVersionProvider myLocalVersionProvider; protected final RemoteComponentVersionProvider myRemoteVersionProvider; + private final RoamingType myRoamingType; + protected ComponentVersionListener myListener = new ComponentVersionListener(){ @Override public void componentStateChanged(String componentName) { @@ -69,18 +75,18 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { private boolean myDisposed; - protected XmlElementStorage(@Nullable TrackingPathMacroSubstitutor pathMacroSubstitutor, + protected XmlElementStorage(@NotNull String fileSpec, + @Nullable RoamingType roamingType, + @Nullable TrackingPathMacroSubstitutor pathMacroSubstitutor, @NotNull Disposable parentDisposable, @NotNull String rootElementName, @Nullable StreamProvider streamProvider, - String fileSpec, - ComponentRoamingManager componentRoamingManager, ComponentVersionProvider componentVersionProvider) { + myFileSpec = fileSpec; + myRoamingType = roamingType == null ? RoamingType.PER_USER : roamingType; myPathMacroSubstitutor = pathMacroSubstitutor; myRootElementName = rootElementName; - myStreamProvider = streamProvider; - myFileSpec = fileSpec; - myComponentRoamingManager = componentRoamingManager; + myStreamProvider = myRoamingType == RoamingType.DISABLED ? null : streamProvider; Disposer.register(parentDisposable, this); myLocalVersionProvider = componentVersionProvider; @@ -92,36 +98,39 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { } @Nullable - protected abstract Document loadDocument() throws StateStorageException; + protected abstract Element loadLocalData(); @Nullable - public synchronized Element getState(final String componentName) throws StateStorageException { + public synchronized Element getState(@NotNull String componentName) { final StorageData storageData = getStorageData(false); final Element state = storageData.getState(componentName); - if (state != null) { if (!myStorageComponentStates.containsKey(componentName)) { myStorageComponentStates.put(componentName, state); } storageData.removeState(componentName); } - return state; } @Override - public boolean hasState(final Object component, final String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException { + public boolean hasState(final Object component, @NotNull String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException { return getStorageData(reloadData).hasState(componentName); } @Override @Nullable - public <T> T getState(final Object component, final String componentName, Class<T> stateClass, @Nullable T mergeInto) throws StateStorageException { + public <T> T getState(final Object component, @NotNull String componentName, Class<T> stateClass, @Nullable T mergeInto) throws StateStorageException { return DefaultStateSerializer.deserializeState(getState(componentName), stateClass, mergeInto); } @NotNull - protected StorageData getStorageData(final boolean reloadData) throws StateStorageException { + protected StorageData getStorageData() { + return getStorageData(false); + } + + @NotNull + private StorageData getStorageData(boolean reloadData) { if (myLoadedData != null && !reloadData) { return myLoadedData; } @@ -131,48 +140,48 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { } @NotNull - protected StorageData loadData(boolean useProvidersData) throws StateStorageException { - Document document = loadDocument(); + protected StorageData loadData(boolean useProvidersData) { StorageData result = createStorageData(); - if (document != null) { - loadState(result, document.getRootElement()); - } - if (useProvidersData && myStreamProvider != null && myStreamProvider.isEnabled()) { - for (RoamingType roamingType : RoamingType.values()) { - if (roamingType != RoamingType.DISABLED && roamingType != RoamingType.GLOBAL) { - try { - Document sharedDocument = StorageUtil.loadDocument(myStreamProvider.loadContent(myFileSpec, roamingType)); - if (sharedDocument != null) { - filterOutOfDate(sharedDocument.getRootElement()); - loadState(result, sharedDocument.getRootElement()); - } - } - catch (Exception e) { - LOG.warn(e); - } - } + boolean wasLoaded = false; + try { + wasLoaded = loadDataFromStreamProvider(result); + } + catch (Exception e) { + LOG.warn(e); + } + + //noinspection deprecation + if (wasLoaded && !myStreamProvider.isVersioningRequired() && !(myStreamProvider instanceof OldStreamProviderAdapter || myStreamProvider instanceof CurrentUserHolder)) { + // we don't use local data if stream provider has one (to preserve backward compatibility, we don't use this logic for old stream providers) + return result; } } + Element element = loadLocalData(); + if (element != null) { + loadState(result, element); + } + return result; } - protected void loadState(final StorageData result, final Element element) throws StateStorageException { - if (myPathMacroSubstitutor != null) { - myPathMacroSubstitutor.expandPaths(element); + private boolean loadDataFromStreamProvider(@NotNull StorageData result) throws IOException, JDOMException { + assert myStreamProvider != null; + InputStream inputStream = myStreamProvider.loadContent(myFileSpec, myRoamingType); + if (inputStream == null) { + return false; } - IdeaPluginDescriptorImpl.internJDOMElement(element); + Element element = JDOMUtil.loadDocument(inputStream).getRootElement(); + filterOutOfDate(element); + loadState(result, element); + return true; + } - try { - result.load(element); - result.checkUnknownMacros(myPathMacroSubstitutor); - } - catch (IOException e) { - throw new StateStorageException(e); - } + private void loadState(@NotNull StorageData result, @NotNull Element element) { + result.load(element, myPathMacroSubstitutor, true); } @NotNull @@ -182,25 +191,15 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { public void setDefaultState(final Element element) { myLoadedData = createStorageData(); - try { - loadState(myLoadedData, element); - } - catch (StateStorageException e) { - LOG.error(e); - } + loadState(myLoadedData, element); } @Override @NotNull public ExternalizationSession startExternalization() { - try { - final ExternalizationSession session = new MyExternalizationSession(getStorageData(false).clone(), myListener); - mySession = session; - return session; - } - catch (StateStorageException e) { - throw new RuntimeException(e); - } + ExternalizationSession session = new MyExternalizationSession(getStorageData().clone(), myListener); + mySession = session; + return session; } @Override @@ -226,19 +225,19 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { @NotNull @Override - public Collection<IFile> getStorageFilesToSave() throws StateStorageException { + public Collection<File> getStorageFilesToSave() throws StateStorageException { return Collections.emptySet(); } @NotNull @Override - public List<IFile> getAllStorageFiles() { + public List<File> getAllStorageFiles() { return Collections.emptyList(); } }; } - protected abstract MySaveSession createSaveSession(final MyExternalizationSession externalizationSession); + protected abstract MySaveSession createSaveSession(MyExternalizationSession externalizationSession); @Override public void finishSave(@NotNull final SaveSession saveSession) { @@ -265,22 +264,26 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { } @Override - public void setState(@NotNull final Object component, final String componentName, @NotNull final Object state, final Storage storageSpec) throws StateStorageException { + public void setState(@NotNull Object component, @NotNull String componentName, @NotNull Object state, @Nullable Storage storageSpec) { assert mySession == this; + Element element; try { - setState(componentName, DefaultStateSerializer.serializeState(state, storageSpec)); + element = DefaultStateSerializer.serializeState(state, storageSpec); } catch (WriteExternalException e) { LOG.debug(e); + return; } - } - private synchronized void setState(final String componentName, final Element element) { - if (element.getAttributes().isEmpty() && element.getChildren().isEmpty()) { + if (element == null || JDOMUtil.isEmpty(element)) { return; } + setState(componentName, element); + } + + private synchronized void setState(@NotNull String componentName, @NotNull Element element) { myStorageData.setState(componentName, element); int hash = JDOMUtil.getTreeHash(element); try { @@ -296,8 +299,12 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { } } - protected Document getDocument(StorageData data) { - final Element element = data.save(); + @Nullable + protected Element getElement(@NotNull StorageData data) { + Element element = data.save(); + if (element == null || JDOMUtil.isEmpty(element)) { + return null; + } if (myPathMacroSubstitutor != null) { try { @@ -308,18 +315,18 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { } } - return new Document(element); + return element; } protected abstract class MySaveSession implements SaveSession, SafeWriteRequestor { final StorageData myStorageData; - private Document myDocumentToSave; + private Element myElementToSave; public MySaveSession(MyExternalizationSession externalizationSession) { myStorageData = externalizationSession.myStorageData; } - public final boolean needsSave() throws StateStorageException { + public final boolean needsSave() { assert mySession == this; return _needsSave(calcHash()); } @@ -382,11 +389,10 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { try { if (myStreamProvider != null && myStreamProvider.isEnabled() && (myProviderUpToDateHash == -1 || myProviderUpToDateHash != hash)) { try { - //noinspection IfStatementWithIdenticalBranches - if (saveForProvider(myStreamProvider)) { - //noinspection UnnecessaryReturnStatement - return; - } + saveForProvider(); + } + catch (IOException e) { + LOG.warn(e); } finally { myProviderUpToDateHash = hash; @@ -398,9 +404,9 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { } } - private void saveLocally(final Integer hash) { + private void saveLocally(int hash) { try { - if (!isHashUpToDate(hash) && _needsSave(hash)) { + if (!(myUpToDateHash != -1 && myUpToDateHash == hash) && _needsSave(hash)) { doSave(); } } @@ -409,15 +415,15 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { } } - private boolean saveForProvider(@NotNull StreamProvider streamProvider) { - if (!streamProvider.isApplicable(myFileSpec, RoamingType.PER_USER)) { - return false; + private void saveForProvider() throws IOException { + if (!myStreamProvider.isApplicable(myFileSpec, myRoamingType)) { + return; } - Document document = getDocumentToSave(); - Element rootElement = document.getRootElement(); - if (rootElement.getChildren().isEmpty()) { - return false; + Element element = getElementToSave(); + if (element == null || element.getChildren().isEmpty()) { + myStreamProvider.delete(myFileSpec, myRoamingType); + return; } // skip the whole document if some component has disabled roaming type @@ -425,59 +431,34 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { // one exclusion: workspace file (you don't have choice in this case) // for example, it is important for ICS ProjectId - we cannot keep project in another place, // but this project id must not be shared - if (!myFileSpec.equals(StoragePathMacros.WORKSPACE_FILE) && - rootElement.getContent(new RoamingElementFilter(RoamingType.DISABLED)).iterator().hasNext()) { - return false; - } - - RoamingElementFilter perPlatformFilter = new RoamingElementFilter(RoamingType.PER_PLATFORM); - if (rootElement.getContent(perPlatformFilter).iterator().hasNext()) { - return doSaveForProvider(rootElement, new RoamingElementFilter(RoamingType.PER_USER)) || - doSaveForProvider(rootElement, perPlatformFilter); + if (myFileSpec.equals(StoragePathMacros.WORKSPACE_FILE)) { + Element copiedElement = JDOMUtil.cloneElement(element, DISABLED_ROAMING_ELEMENT_FILTER); + if (copiedElement != null) { + doSaveForProvider(copiedElement, DISABLED_ROAMING_ELEMENT_FILTER.myRoamingType, myStreamProvider); + } } else { - return doSaveForProvider(document, RoamingType.PER_USER, streamProvider); + doSaveForProvider(element, myRoamingType, myStreamProvider); } } - private boolean doSaveForProvider(Element element, RoamingElementFilter filter) { - Element copiedElement = JDOMUtil.cloneElement(element, filter); - return copiedElement != null && doSaveForProvider(new Document(copiedElement), filter.myRoamingType, myStreamProvider); - } - - private boolean doSaveForProvider(Document actualDocument, RoamingType roamingType, StreamProvider streamProvider) { - try { - boolean result = StorageUtil.doSendContent(streamProvider, myFileSpec, actualDocument, roamingType, true); - if (streamProvider.isVersioningRequired()) { - TObjectLongHashMap<String> versions = loadVersions(actualDocument.getRootElement().getChildren(StorageData.COMPONENT)); - if (!versions.isEmpty()) { - Document versionDoc = new Document(StateStorageManagerImpl.createComponentVersionsXml(versions)); - StorageUtil.doSendContent(streamProvider, myFileSpec + VERSION_FILE_SUFFIX, versionDoc, roamingType, true); - } + private void doSaveForProvider(@NotNull Element element, @NotNull RoamingType roamingType, @NotNull StreamProvider streamProvider) throws IOException { + StorageUtil.doSendContent(streamProvider, myFileSpec, element, roamingType, true); + if (streamProvider.isVersioningRequired()) { + TObjectLongHashMap<String> versions = loadVersions(element.getChildren(StorageData.COMPONENT)); + if (!versions.isEmpty()) { + Element versionDoc = StateStorageManagerImpl.createComponentVersionsXml(versions); + StorageUtil.doSendContent(streamProvider, myFileSpec + VERSION_FILE_SUFFIX, versionDoc, roamingType, true); } - return result; - } - catch (IOException e) { - LOG.warn(e); - return false; } } - private boolean isHashUpToDate(final Integer hash) { - return myUpToDateHash != -1 && myUpToDateHash == hash; - } - - protected Document getDocumentToSave() { - if (myDocumentToSave != null) return myDocumentToSave; - - final Element element = myStorageData.save(); - myDocumentToSave = new Document(element); - - if (myPathMacroSubstitutor != null) { - myPathMacroSubstitutor.collapsePaths(element); + @Nullable + protected Element getElementToSave() { + if (myElementToSave == null) { + myElementToSave = getElement(myStorageData); } - - return myDocumentToSave; + return myElementToSave; } public StorageData getData() { @@ -488,12 +469,12 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { @Nullable public Set<String> analyzeExternalChanges(@NotNull final Set<Pair<VirtualFile,StateStorage>> changedFiles) { try { - Document document = loadDocument(); + Element element = loadLocalData(); StorageData storageData = createStorageData(); - if (document == null) { + if (element == null) { return Collections.emptySet(); } - loadState(storageData, document.getRootElement()); + loadState(storageData, element); return storageData.getDifference(myStorageData, myPathMacroSubstitutor); } catch (StateStorageException e) { @@ -502,21 +483,6 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { return null; } - - private class RoamingElementFilter extends ElementFilter { - final RoamingType myRoamingType; - - public RoamingElementFilter(RoamingType roamingType) { - super(StorageData.COMPONENT); - - myRoamingType = roamingType; - } - - @Override - public boolean matches(Object obj) { - return super.matches(obj) && myComponentRoamingManager.getRoamingType(((Element)obj).getAttributeValue(StorageData.NAME)) == myRoamingType; - } - } } private TObjectLongHashMap<String> loadVersions(List<Element> elements) { @@ -545,11 +511,9 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { @Override public void reload(@NotNull final Set<String> changedComponents) throws StateStorageException { final StorageData storageData = loadData(false); - final StorageData oldLoadedData = myLoadedData; - if (oldLoadedData != null) { - Set<String> componentsToRetain = new HashSet<String>(oldLoadedData.myComponentStates.keySet()); + Set<String> componentsToRetain = new THashSet<String>(oldLoadedData.myComponentStates.keySet()); componentsToRetain.addAll(changedComponents); // add empty configuration tags for removed components @@ -568,7 +532,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { myLoadedData = storageData; } - private void filterOutOfDate(Element element) { + private void filterOutOfDate(@NotNull Element element) { if (myRemoteVersionProvider == null) { return; } @@ -587,12 +551,19 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { } @Nullable - Document logComponents() throws StateStorageException { - return mySession instanceof MySaveSession ? getDocument(((MySaveSession)mySession).myStorageData) : null; + Element logComponents() { + return mySession instanceof MySaveSession ? getElement(((MySaveSession)mySession).myStorageData) : null; } - protected class RemoteComponentVersionProvider implements ComponentVersionProvider { - protected TObjectLongHashMap<String> myProviderVersions; + public void resetProviderCache() { + myProviderUpToDateHash = -1; + if (myRemoteVersionProvider != null) { + myRemoteVersionProvider.myProviderVersions = null; + } + } + + private final class RemoteComponentVersionProvider implements ComponentVersionProvider { + private TObjectLongHashMap<String> myProviderVersions; @Override public long getVersion(String name) { @@ -632,4 +603,19 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { } } } + + private static class RoamingElementFilter extends ElementFilter { + final RoamingType myRoamingType; + + public RoamingElementFilter(RoamingType roamingType) { + super(StorageData.COMPONENT); + + myRoamingType = roamingType; + } + + @Override + public boolean matches(Object obj) { + return super.matches(obj) && ComponentRoamingManager.getInstance().getRoamingType(((Element)obj).getAttributeValue(StorageData.NAME)) == myRoamingType; + } + } } |