summaryrefslogtreecommitdiff
path: root/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java
diff options
context:
space:
mode:
Diffstat (limited to 'platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java')
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java304
1 files changed, 145 insertions, 159 deletions
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;
+ }
+ }
}