settings stream provider — ability to reload to apply updated settings

This commit is contained in:
Vladimir Krivosheev
2014-09-23 11:19:40 +02:00
parent fe5d50b303
commit 1adfa139fa
24 changed files with 333 additions and 252 deletions
@@ -21,6 +21,7 @@ import com.intellij.util.PlatformUtilsCore;
import org.jdom.Document;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
/**
* @author nik
@@ -42,6 +43,7 @@ public class ApplicationNamesInfo {
private ApplicationNamesInfoHolder() { }
}
@NotNull
public static ApplicationNamesInfo getInstance() {
return ApplicationNamesInfoHolder.ourInstance;
}
@@ -158,12 +158,14 @@ public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IM
return super.computeHash() * 31 + myOptions.hashCode();
}
@Override
@Nullable
public Set<String> getDifference(final StorageData storageData, PathMacroSubstitutor substitutor) {
@Override
public Set<String> getChangedComponentNames(@NotNull StorageData storageData, @Nullable PathMacroSubstitutor substitutor) {
final ModuleFileData data = (ModuleFileData)storageData;
if (!myOptions.equals(data.myOptions)) return null;
return super.getDifference(storageData, substitutor);
if (!myOptions.equals(data.myOptions)) {
return null;
}
return super.getChangedComponentNames(storageData, substitutor);
}
public void setOption(final String optionName, final String optionValue) {
@@ -89,14 +89,9 @@ public class ProjectWithModulesStoreImpl extends ProjectStoreImpl {
private class ProjectWithModulesSaveSession extends ProjectSaveSession {
List<SaveSession> myModuleSaveSessions = new ArrayList<SaveSession>();
public ProjectWithModulesSaveSession() throws StateStorageException {
try {
for (Module module : getPersistentModules()) {
myModuleSaveSessions.add(((ModuleImpl)module).getStateStore().startSave());
}
}
catch (IOException e) {
throw new StateStorageException(e.getMessage());
public ProjectWithModulesSaveSession() {
for (Module module : getPersistentModules()) {
myModuleSaveSessions.add(((ModuleImpl)module).getStateStore().startSave());
}
}
@@ -207,7 +207,7 @@ public class ClasspathStorage implements StateStorage {
}
@Override
public void reload(@NotNull final Set<String> changedComponents) throws StateStorageException {
public void reload(@NotNull Set<String> changedComponents) {
}
public boolean needsSave() throws StateStorageException {
@@ -28,7 +28,6 @@ import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
class ApplicationStoreImpl extends ComponentStoreImpl implements IApplicationStore {
@@ -133,47 +132,8 @@ class ApplicationStoreImpl extends ComponentStoreImpl implements IApplicationSto
}
@Override
public boolean reload(@NotNull final Set<Pair<VirtualFile, StateStorage>> changedFiles,
@NotNull final Collection<String> notReloadableComponents) throws StateStorageException, IOException {
final SaveSession saveSession = startSave();
final Set<String> componentNames = saveSession.analyzeExternalChanges(changedFiles);
try {
if (componentNames == null) return false;
for (Pair<VirtualFile, StateStorage> pair : changedFiles) {
if (pair.second == null) return false;
}
for (String name : componentNames) {
if (!isReloadPossible(Collections.singleton(name))) {
notReloadableComponents.add(name);
}
}
StorageUtil.logStateDiffInfo(changedFiles, componentNames);
if (!isReloadPossible(componentNames)) {
return false;
}
}
finally {
finishSave(saveSession);
}
if (!componentNames.isEmpty()) {
myApplication.getMessageBus().syncPublisher(BatchUpdateListener.TOPIC).onBatchUpdateStarted();
try {
doReload(changedFiles, componentNames);
reinitComponents(componentNames, false);
}
finally {
myApplication.getMessageBus().syncPublisher(BatchUpdateListener.TOPIC).onBatchUpdateFinished();
}
}
return true;
public Collection<String> reload(@NotNull Set<Pair<VirtualFile, StateStorage>> changedFiles) throws IOException {
return reload(changedFiles, myApplication.getMessageBus());
}
@NotNull
@@ -95,12 +95,14 @@ abstract class BaseFileConfigurableStoreImpl extends ComponentStoreImpl {
return result;
}
@Override
@Nullable
public Set<String> getDifference(final StorageData storageData, PathMacroSubstitutor substitutor) {
final BaseStorageData data = (BaseStorageData)storageData;
if (myVersion != data.myVersion) return null;
return super.getDifference(storageData, substitutor);
@Override
public Set<String> getChangedComponentNames(@NotNull StorageData storageData, @Nullable PathMacroSubstitutor substitutor) {
BaseStorageData data = (BaseStorageData)storageData;
if (myVersion != data.myVersion) {
return null;
}
return super.getChangedComponentNames(storageData, substitutor);
}
}
@@ -29,6 +29,7 @@ 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.messages.MessageBus;
import gnu.trove.THashMap;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
@@ -90,37 +91,28 @@ public abstract class ComponentStoreImpl implements IComponentStore {
@Override
@NotNull
public SaveSession startSave() throws IOException {
public SaveSession startSave() {
SaveSessionImpl session = createSaveSession();
try {
final SaveSessionImpl session = createSaveSession();
session.commit();
}
catch (Throwable e) {
try {
session.commit();
session.reset();
}
catch (Throwable e) {
try {
session.reset();
}
catch (Exception e1_ignored) {
LOG.info(e1_ignored);
}
PluginId pluginId = IdeErrorsDialog.findPluginId(e);
if (pluginId != null) {
throw new PluginException(e, pluginId);
}
LOG.info(e);
IOException ioException = new IOException(e.getMessage());
ioException.initCause(e);
throw ioException;
catch (Exception e1_ignored) {
LOG.info(e1_ignored);
}
mySession = session;
return mySession;
}
catch (StateStorageException e) {
LOG.info(e);
throw new IOException(e.getMessage());
PluginId pluginId = IdeErrorsDialog.findPluginId(e);
if (pluginId != null) {
throw new PluginException(e, pluginId);
}
throw new StateStorageException(e);
}
mySession = session;
return mySession;
}
protected SaveSessionImpl createSaveSession() throws StateStorageException {
@@ -460,6 +452,22 @@ public abstract class ComponentStoreImpl implements IComponentStore {
return true;
}
@Override
@NotNull
public final Collection<String> getNotReloadableComponents(@NotNull Collection<String> componentNames) {
Set<String> notReloadableComponents = null;
for (String componentName : componentNames) {
Object component = myComponents.get(componentName);
if (component != null && (!(component instanceof PersistentStateComponent) || !getStateSpec((PersistentStateComponent<?>)component).reloadable())) {
if (notReloadableComponents == null) {
notReloadableComponents = new LinkedHashSet<String>();
}
notReloadableComponents.add(componentName);
}
}
return notReloadableComponents == null ? Collections.<String>emptySet() : notReloadableComponents;
}
@Override
public void reinitComponents(@NotNull final Set<String> componentNames, final boolean reloadData) {
for (String componentName : componentNames) {
@@ -470,13 +478,55 @@ public abstract class ComponentStoreImpl implements IComponentStore {
}
}
protected void doReload(final Set<Pair<VirtualFile, StateStorage>> changedFiles, @NotNull final Set<String> componentNames)
throws StateStorageException {
protected void doReload(@NotNull Set<Pair<VirtualFile, StateStorage>> changedFiles, @NotNull Set<String> componentNames) {
for (Pair<VirtualFile, StateStorage> pair : changedFiles) {
assert pair != null;
final StateStorage storage = pair.second;
StateStorage storage = pair.second;
assert storage != null : "Null storage for: " + pair.first;
storage.reload(componentNames);
}
}
@Nullable
protected final Collection<String> reload(@NotNull Set<Pair<VirtualFile, StateStorage>> changedFiles, @NotNull MessageBus messageBus) {
SaveSession saveSession = startSave();
Set<String> componentNames;
try {
componentNames = saveSession.analyzeExternalChanges(changedFiles);
if (componentNames == null) {
return Collections.emptyList();
}
for (Pair<VirtualFile, StateStorage> pair : changedFiles) {
if (pair.second == null) {
return Collections.emptyList();
}
}
Collection<String> currentNotReloadableComponents = getNotReloadableComponents(componentNames);
StorageUtil.logStateDiffInfo(changedFiles, componentNames);
if (!currentNotReloadableComponents.isEmpty()) {
return currentNotReloadableComponents;
}
}
finally {
finishSave(saveSession);
}
if (!componentNames.isEmpty()) {
messageBus.syncPublisher(BatchUpdateListener.TOPIC).onBatchUpdateStarted();
try {
doReload(changedFiles, componentNames);
reinitComponents(componentNames, false);
}
finally {
messageBus.syncPublisher(BatchUpdateListener.TOPIC).onBatchUpdateFinished();
}
}
return null;
}
}
@@ -19,6 +19,7 @@ import com.intellij.openapi.components.*;
import com.intellij.openapi.options.StreamProvider;
import com.intellij.openapi.project.impl.ProjectImpl;
import com.intellij.openapi.project.impl.ProjectManagerImpl;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import org.jdom.Element;
@@ -137,6 +138,12 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl {
return storage;
}
@NotNull
@Override
public Couple<Collection<FileBasedStorage>> getCachedFileStateStorages(@NotNull Collection<String> changed, @NotNull Collection<String> deleted) {
return new Couple<Collection<FileBasedStorage>>(Collections.<FileBasedStorage>emptyList(), Collections.<FileBasedStorage>emptyList());
}
@Override
@Nullable
public StateStorage getFileStateStorage(@NotNull String fileSpec) {
@@ -89,7 +89,7 @@ class DefaultsStateStorage implements StateStorage {
throw new UnsupportedOperationException("Method finishSave not implemented in " + getClass());
}
public void reload(@NotNull final Set<String> changedComponents) throws StateStorageException {
public void reload(@NotNull Set<String> changedComponents) {
throw new UnsupportedOperationException("Method reload not implemented in " + getClass());
}
@@ -24,11 +24,13 @@ import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.util.text.StringUtilRt;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.tracker.VirtualFileTracker;
import com.intellij.util.SmartList;
import com.intellij.util.containers.SmartHashSet;
import com.intellij.util.messages.MessageBus;
import gnu.trove.THashSet;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -106,7 +108,7 @@ public class DirectoryBasedStorage implements StateStorage, Disposable {
return myStorageData.getMergedState(componentName, stateClass, mySplitter, mergeInto);
}
private DirectoryStorageData loadState() throws StateStorageException {
private DirectoryStorageData loadState() {
DirectoryStorageData storageData = new DirectoryStorageData();
storageData.loadFrom(LocalFileSystem.getInstance().findFileByIoFile(myDir), myPathMacroSubstitutor);
return storageData;
@@ -158,7 +160,7 @@ public class DirectoryBasedStorage implements StateStorage, Disposable {
}
@Override
public void reload(@NotNull final Set<String> changedComponents) throws StateStorageException {
public void reload(@NotNull Set<String> changedComponents) {
myStorageData = loadState();
}
@@ -239,28 +241,28 @@ public class DirectoryBasedStorage implements StateStorage, Disposable {
@Override
@Nullable
public Set<String> analyzeExternalChanges(@NotNull final Set<Pair<VirtualFile, StateStorage>> changedFiles) {
public Set<String> analyzeExternalChanges(@NotNull Set<Pair<VirtualFile, StateStorage>> changedFiles) {
boolean containsSelf = false;
for (Pair<VirtualFile, StateStorage> pair : changedFiles) {
if (pair.second == DirectoryBasedStorage.this) {
VirtualFile file = pair.first;
if ("xml".equalsIgnoreCase(file.getExtension())) {
if (StringUtilRt.endsWithIgnoreCase(pair.first.getNameSequence(), ".xml")) {
containsSelf = true;
break;
}
}
}
if (!containsSelf) return Collections.emptySet();
if (myStorageData.getComponentNames().size() == 0) {
// no state yet, so try to initialize it now
final DirectoryStorageData storageData = loadState();
return new HashSet<String>(storageData.getComponentNames());
if (!containsSelf) {
return Collections.emptySet();
}
return new HashSet<String>(myStorageData.getComponentNames());
if (myStorageData.getComponentNames().isEmpty()) {
// no state yet, so try to initialize it now
return new THashSet<String>(loadState().getComponentNames());
}
else {
return new THashSet<String>(myStorageData.getComponentNames());
}
}
@Override
@@ -40,6 +40,7 @@ import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
public class FileBasedStorage extends XmlElementStorage {
private static final Logger LOG = Logger.getInstance(FileBasedStorage.class);
@@ -262,7 +263,33 @@ public class FileBasedStorage extends XmlElementStorage {
super.setDefaultState(element);
}
public void updatedFromStreamProvider(@NotNull Set<String> changedComponentNames, boolean deleted) {
resetProviderCache();
try {
Element newElement = deleted ? null : loadDataFromStreamProvider();
if (newElement == null) {
StorageUtil.deleteFile(myFile, this, myCachedVirtualFile);
// if data was loaded, mark as changed all loaded components
if (myLoadedData != null) {
changedComponentNames.addAll(myLoadedData.myComponentStates.keySet());
resetData();
}
}
else if (myLoadedData != null) {
StorageData newStorageData = createStorageData();
loadState(newStorageData, newElement);
changedComponentNames.addAll(newStorageData.getChangedComponentNames(myLoadedData, myPathMacroSubstitutor));
myLoadedData = newStorageData;
}
}
catch (Exception e) {
LOG.warn(e);
}
}
@Nullable
@Deprecated
public File updateFileExternallyFromStreamProviders() throws IOException {
Element element = getElement(loadData(true));
if (element == null) {
@@ -16,10 +16,10 @@
package com.intellij.openapi.components.impl.stores;
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 org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.Collection;
@@ -33,6 +33,11 @@ public interface IApplicationStore extends IComponentStore {
void setConfigPath(@NotNull String configPath);
boolean reload(@NotNull Set<Pair<VirtualFile, StateStorage>> changedFiles, @NotNull Collection<String> notReloadableComponents)
throws StateStorageException, IOException;
/**
* null if reloaded
* empty list if nothing to reload
* list of not reloadable components (reload is not performed)
*/
@Nullable
Collection<String> reload(@NotNull Set<Pair<VirtualFile, StateStorage>> changedFiles) throws IOException;
}
@@ -24,15 +24,22 @@ import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Set;
public interface IComponentStore {
void initComponent(@NotNull Object component, boolean service);
void reinitComponents(@NotNull Set<String> componentNames, boolean reloadData);
@NotNull
Collection<String> getNotReloadableComponents(@NotNull Collection<String> componentNames);
boolean isReloadPossible(@NotNull Set<String> componentNames);
void load() throws IOException, StateStorageException;
boolean isSaving();
@NotNull
@@ -48,9 +55,8 @@ public interface IComponentStore {
}
}
//todo:remove throws
@NotNull
SaveSession startSave() throws IOException;
SaveSession startSave();
interface SaveSession {
@NotNull
@@ -55,7 +55,7 @@ public interface IProjectStore extends IComponentStore {
@Nullable
String getPresentableUrl();
boolean reload(@NotNull Set<Pair<VirtualFile,StateStorage>> changedFiles) throws StateStorageException, IOException;
boolean reload(@NotNull Set<Pair<VirtualFile,StateStorage>> changedFiles) throws IOException;
//------ This methods should be got rid of
/** @deprecated to remove in IDEA 14 */
@@ -691,43 +691,7 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
}
@Override
public boolean reload(@NotNull final Set<Pair<VirtualFile, StateStorage>> changedFiles) throws IOException, StateStorageException {
final SaveSession saveSession = startSave();
final Set<String> componentNames;
try {
componentNames = saveSession.analyzeExternalChanges(changedFiles);
if (componentNames == null) return false;
// TODO[mike]: This is a hack to prevent NPE (assert != null) in StateStorageManagerImpl.reload, storage is null for...
for (Pair<VirtualFile, StateStorage> pair : changedFiles) {
if (pair.second == null) {
return false;
}
}
StorageUtil.logStateDiffInfo(changedFiles, componentNames);
if (!isReloadPossible(componentNames)) {
return false;
}
}
finally {
finishSave(saveSession);
}
if (!componentNames.isEmpty()) {
myProject.getMessageBus().syncPublisher(BatchUpdateListener.TOPIC).onBatchUpdateStarted();
try {
doReload(changedFiles, componentNames);
reinitComponents(componentNames, false);
}
finally {
myProject.getMessageBus().syncPublisher(BatchUpdateListener.TOPIC).onBatchUpdateFinished();
}
}
return true;
public boolean reload(@NotNull Set<Pair<VirtualFile, StateStorage>> changedFiles) throws IOException {
return reload(changedFiles, myProject.getMessageBus()) == null;
}
}
@@ -17,6 +17,7 @@ package com.intellij.openapi.components.impl.stores;
import com.intellij.openapi.components.*;
import com.intellij.openapi.options.StreamProvider;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
@@ -42,13 +43,18 @@ public interface StateStorageManager {
@Nullable
StateStorage getStateStorage(@NotNull String fileSpec, @NotNull RoamingType roamingType);
@SuppressWarnings("UnusedDeclaration")
@Deprecated
@Nullable
/**
* @deprecated Use {@link #getStateStorage(String, com.intellij.openapi.components.RoamingType)}
* to remove in IDEA 15
*/
StateStorage getFileStateStorage(@NotNull String fileSpec);
@NotNull
Couple<Collection<FileBasedStorage>> getCachedFileStateStorages(@NotNull Collection<String> changed, @NotNull Collection<String> deleted);
@NotNull
Collection<String> getStorageFileNames();
@@ -87,7 +93,7 @@ public interface StateStorageManager {
}
interface SaveSession {
//returns set of component which were changed, null if changes are much more than just component state.
// returns set of component which were changed, null if changes are much more than just component state
@Nullable
Set<String> analyzeExternalChanges(@NotNull Set<Pair<VirtualFile, StateStorage>> files);
@@ -21,10 +21,7 @@ import com.intellij.openapi.application.ApplicationManager;
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.RoamingTypeDisabled;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
@@ -153,6 +150,37 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
return getStateStorage(fileSpec, RoamingType.PER_USER);
}
@NotNull
@Override
public Couple<Collection<FileBasedStorage>> getCachedFileStateStorages(@NotNull Collection<String> changed, @NotNull Collection<String> deleted) {
myStorageLock.lock();
try {
return Couple.of(getCachedFileStorages(changed), getCachedFileStorages(deleted));
}
finally {
myStorageLock.unlock();
}
}
@NotNull
private Collection<FileBasedStorage> getCachedFileStorages(@NotNull Collection<String> fileSpecs) {
if (fileSpecs.isEmpty()) {
return Collections.emptyList();
}
List<FileBasedStorage> result = null;
for (String fileSpec : fileSpecs) {
StateStorage storage = myStorages.get(fileSpec);
if (storage instanceof FileBasedStorage) {
if (result == null) {
result = new SmartList<FileBasedStorage>();
}
result.add((FileBasedStorage)storage);
}
}
return result == null ? Collections.<FileBasedStorage>emptyList() : result;
}
@NotNull
@Override
public Collection<String> getStorageFileNames() {
@@ -480,23 +508,27 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
}
}
//returns set of component which were changed, null if changes are much more than just component state.
@Override
@Nullable
public Set<String> analyzeExternalChanges(@NotNull final Set<Pair<VirtualFile, StateStorage>> changedFiles) {
Set<String> result = new THashSet<String>();
public Set<String> analyzeExternalChanges(@NotNull Set<Pair<VirtualFile, StateStorage>> changedFiles) {
Set<String> result = null;
for (Pair<VirtualFile, StateStorage> pair : changedFiles) {
final StateStorage.SaveSession saveSession = myCompoundSaveSession.getSaveSession(pair.second);
StateStorage.SaveSession saveSession = myCompoundSaveSession.getSaveSession(pair.second);
if (saveSession == null) {
continue;
}
final Set<String> changes = saveSession.analyzeExternalChanges(changedFiles);
Set<String> changes = saveSession.analyzeExternalChanges(changedFiles);
if (changes == null) {
return null;
}
if (result == null) {
result = new THashSet<String>();
}
result.addAll(changes);
}
return result;
return result == null ? Collections.<String>emptySet() : result;
}
}
@@ -127,31 +127,13 @@ public class StorageUtil {
* 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 File file, @Nullable Parent element, Object requestor, boolean wrapAsDocument, @Nullable VirtualFile cachedVirtualFile) throws StateStorageException {
static VirtualFile save(@NotNull File file, @Nullable Parent element, @NotNull Object requestor, boolean wrapAsDocument, @Nullable VirtualFile cachedVirtualFile) throws StateStorageException {
if (isEmpty(element)) {
if (!file.exists()) {
return null;
try {
deleteFile(file, requestor, cachedVirtualFile);
}
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 {
AccessToken token = ApplicationManager.getApplication().acquireWriteActionLock(DocumentRunnable.IgnoreDocumentRunnable.class);
try {
virtualFile.delete(requestor);
}
catch (IOException e) {
throw new StateStorageException(e);
}
finally {
token.finish();
}
catch (IOException e) {
throw new StateStorageException(e);
}
return null;
}
@@ -200,6 +182,30 @@ public class StorageUtil {
}
}
public static void deleteFile(@NotNull File file, @NotNull Object requestor, @Nullable VirtualFile cachedVirtualFile) throws IOException {
if (!file.exists()) {
return;
}
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 {
AccessToken token = ApplicationManager.getApplication().acquireWriteActionLock(DocumentRunnable.IgnoreDocumentRunnable.class);
try {
virtualFile.delete(requestor);
}
finally {
token.finish();
}
}
}
@NotNull
private static BufferExposingByteArrayOutputStream writeToBytes(@NotNull Parent element, @NotNull String lineSeparator) throws IOException {
BufferExposingByteArrayOutputStream out = new BufferExposingByteArrayOutputStream(512);
@@ -15,6 +15,8 @@
*/
package com.intellij.openapi.components.impl.stores;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
/**
@@ -24,7 +26,7 @@ public class StoreUtil {
private StoreUtil() {
}
public static void doSave(IComponentStore stateStore) throws IOException {
public static void doSave(@NotNull IComponentStore stateStore) throws IOException {
IComponentStore.SaveSession session = null;
try {
session = stateStore.startSave();
@@ -51,7 +51,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
protected TrackingPathMacroSubstitutor myPathMacroSubstitutor;
@NotNull protected final String myRootElementName;
private Object mySession;
private StorageData myLoadedData;
protected StorageData myLoadedData;
protected final StreamProvider myStreamProvider;
protected final String myFileSpec;
protected boolean myBlockSavingTheContent = false;
@@ -145,7 +145,10 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
if (useProvidersData && myStreamProvider != null && myStreamProvider.isEnabled()) {
try {
loadDataFromStreamProvider(result);
Element element = loadDataFromStreamProvider();
if (element != null) {
loadState(result, element);
}
//noinspection deprecation
if (!myStreamProvider.isVersioningRequired() && !(myStreamProvider instanceof OldStreamProviderAdapter || myStreamProvider instanceof CurrentUserHolder)) {
@@ -166,19 +169,20 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
return result;
}
private void loadDataFromStreamProvider(@NotNull StorageData result) throws IOException, JDOMException {
@Nullable
protected final Element loadDataFromStreamProvider() throws IOException, JDOMException {
assert myStreamProvider != null;
InputStream inputStream = myStreamProvider.loadContent(myFileSpec, myRoamingType);
if (inputStream == null) {
return;
return null;
}
Element element = JDOMUtil.loadDocument(inputStream).getRootElement();
filterOutOfDate(element);
loadState(result, element);
return element;
}
private void loadState(@NotNull StorageData result, @NotNull Element element) {
protected final void loadState(@NotNull StorageData result, @NotNull Element element) {
result.load(element, myPathMacroSubstitutor, true);
}
@@ -465,15 +469,28 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
@Override
@Nullable
public Set<String> analyzeExternalChanges(@NotNull final Set<Pair<VirtualFile,StateStorage>> changedFiles) {
public Set<String> analyzeExternalChanges(@NotNull Set<Pair<VirtualFile, StateStorage>> changedFiles) {
boolean containsSelf = false;
for (Pair<VirtualFile, StateStorage> pair : changedFiles) {
if (pair.second == XmlElementStorage.this) {
containsSelf = true;
break;
}
}
if (!containsSelf) {
return Collections.emptySet();
}
try {
Element element = loadLocalData();
StorageData storageData = createStorageData();
if (element == null) {
return Collections.emptySet();
}
StorageData storageData = createStorageData();
loadState(storageData, element);
return storageData.getDifference(myStorageData, myPathMacroSubstitutor);
return storageData.getChangedComponentNames(myStorageData, myPathMacroSubstitutor);
}
catch (StateStorageException e) {
LOG.info(e);
@@ -507,7 +524,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
}
@Override
public void reload(@NotNull final Set<String> changedComponents) throws StateStorageException {
public void reload(@NotNull final Set<String> changedComponents) {
final StorageData storageData = loadData(false);
final StorageData oldLoadedData = myLoadedData;
if (oldLoadedData != null) {
@@ -33,7 +33,6 @@ import com.intellij.openapi.components.StateStorage;
import com.intellij.openapi.components.StateStorageException;
import com.intellij.openapi.components.TrackingPathMacroSubstitutor;
import com.intellij.openapi.components.impl.stores.IComponentStore;
import com.intellij.openapi.components.impl.stores.IProjectStore;
import com.intellij.openapi.components.impl.stores.StorageUtil;
import com.intellij.openapi.components.impl.stores.XmlElementStorage;
import com.intellij.openapi.diagnostic.Logger;
@@ -54,6 +53,7 @@ import com.intellij.openapi.vfs.impl.local.LocalFileSystemImpl;
import com.intellij.openapi.wm.impl.welcomeScreen.WelcomeFrame;
import com.intellij.util.Alarm;
import com.intellij.util.ArrayUtil;
import com.intellij.util.SmartList;
import com.intellij.util.TimeoutUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
@@ -98,7 +98,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
private final Map<Project, List<Pair<VirtualFile, StateStorage>>> myChangedProjectFiles =
new HashMap<Project, List<Pair<VirtualFile, StateStorage>>>();
private final Alarm myChangedFilesAlarm = new Alarm();
private final List<Pair<VirtualFile, StateStorage>> myChangedApplicationFiles = new ArrayList<Pair<VirtualFile, StateStorage>>();
private final List<Pair<VirtualFile, StateStorage>> myChangedApplicationFiles = new SmartList<Pair<VirtualFile, StateStorage>>();
private final AtomicInteger myReloadBlockCount = new AtomicInteger(0);
private final ProgressManager myProgressManager;
private volatile boolean myDefaultProjectWasDisposed = false;
@@ -120,11 +120,8 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
messageBus.connect(app).subscribe(StateStorage.STORAGE_TOPIC, new StateStorage.Listener() {
@Override
public void storageFileChanged(@NotNull final VirtualFileEvent event, @NotNull final StateStorage storage) {
VirtualFile file = event.getFile();
if (!file.isDirectory() && !(event.getRequestor() instanceof StateStorage.SaveSession)) {
saveChangedProjectFile(file, null, storage);
}
public void storageFileChanged(@NotNull VirtualFileEvent event, @NotNull StateStorage storage) {
projectStorageFileChanged(event, storage, null);
}
});
@@ -138,10 +135,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
connection.subscribe(StateStorage.STORAGE_TOPIC, new StateStorage.Listener() {
@Override
public void storageFileChanged(@NotNull final VirtualFileEvent event, @NotNull final StateStorage storage) {
VirtualFile file = event.getFile();
if (!file.isDirectory() && !(event.getRequestor() instanceof StateStorage.SaveSession)) {
saveChangedProjectFile(file, project, storage);
}
projectStorageFileChanged(event, storage, project);
}
});
@@ -182,6 +176,13 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
registerExternalProjectFileListener(virtualFileManager);
}
private void projectStorageFileChanged(@NotNull VirtualFileEvent event, @NotNull StateStorage storage, @Nullable Project project) {
VirtualFile file = event.getFile();
if (!file.isDirectory() && !(event.getRequestor() instanceof StateStorage.SaveSession)) {
registerProjectToReload(project, file, storage);
}
}
@Override
public void initComponent() { }
@@ -242,6 +243,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
String message = e.getMessage();
if (message != null) return message;
message = e.getLocalizedMessage();
//noinspection ConstantConditions
if (message != null) return message;
message = e.toString();
Throwable cause = e.getCause();
@@ -641,34 +643,35 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
private boolean tryToReloadApplication() {
try {
final Application app = ApplicationManager.getApplication();
if (app.isDisposed()) {
return false;
}
final Set<Pair<VirtualFile, StateStorage>> causes = new THashSet<Pair<VirtualFile, StateStorage>>(myChangedApplicationFiles);
if (causes.isEmpty()) {
return true;
}
if (app.isDisposed()) return false;
final HashSet<Pair<VirtualFile, StateStorage>> causes = new HashSet<Pair<VirtualFile, StateStorage>>(myChangedApplicationFiles);
if (causes.isEmpty()) return true;
final boolean[] reloadOk = {false};
final LinkedHashSet<String> components = new LinkedHashSet<String>();
final Ref<Collection<String>> reloadResult = Ref.create();
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
try {
reloadOk[0] = ((ApplicationImpl)app).getStateStore().reload(causes, components);
reloadResult.set(((ApplicationImpl)app).getStateStore().reload(causes));
}
catch (StateStorageException e) {
Messages.showWarningDialog(ProjectBundle.message("project.reload.failed", e.getMessage()),
ProjectBundle.message("project.reload.failed.title"));
}
catch (IOException e) {
catch (Exception e) {
Messages.showWarningDialog(ProjectBundle.message("project.reload.failed", e.getMessage()),
ProjectBundle.message("project.reload.failed.title"));
}
}
});
if (!reloadOk[0] && !components.isEmpty()) {
if (reloadResult.isNull()) {
return true;
}
if (!reloadResult.get().isEmpty()) {
String message = "Application components were changed externally and cannot be reloaded:\n";
for (String component : components) {
for (String component : reloadResult.get()) {
message += component + "\n";
}
@@ -687,8 +690,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
ApplicationManagerEx.getApplicationEx().restart(true);
}
}
return reloadOk[0];
return false;
}
finally {
myChangedApplicationFiles.clear();
@@ -788,8 +790,9 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
if (!tryToReloadApplication()) return;
askToReloadProjectIfConfigFilesChangedExternally();
if (tryToReloadApplication()) {
askToReloadProjectIfConfigFilesChangedExternally();
}
}
}, ModalityState.NON_MODAL);
//}
@@ -818,20 +821,21 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
@Override
public void saveChangedProjectFile(@NotNull VirtualFile file, @Nullable Project project) {
if (file.exists()) {
copyToTemp(file);
}
registerProjectToReload(project, file, null);
}
private void saveChangedProjectFile(final VirtualFile file, @Nullable final Project project, final StateStorage storage) {
if (file.exists()) {
copyToTemp(file);
}
registerProjectToReload(project, file, storage);
}
private void registerProjectToReload(@Nullable Project project, VirtualFile cause, @Nullable StateStorage storage) {
if (cause.exists()) {
try {
byte[] bytes = cause.contentsToByteArray();
mySavedCopies.put(cause, bytes);
mySavedTimestamps.put(cause, cause.getTimeStamp());
}
catch (IOException e) {
LOG.error(e);
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("[RELOAD] Registering project to reload: " + cause, new Exception());
}
@@ -840,7 +844,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
synchronized (myChangedProjectFiles) {
List<Pair<VirtualFile, StateStorage>> changedProjectFiles = myChangedProjectFiles.get(project);
if (changedProjectFiles == null) {
changedProjectFiles = new ArrayList<Pair<VirtualFile, StateStorage>>();
changedProjectFiles = new SmartList<Pair<VirtualFile, StateStorage>>();
myChangedProjectFiles.put(project, changedProjectFiles);
}
@@ -863,17 +867,6 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
}, 444);
}
private void copyToTemp(VirtualFile file) {
try {
final byte[] bytes = file.contentsToByteArray();
mySavedCopies.put(file, bytes);
mySavedTimestamps.put(file, file.getTimeStamp());
}
catch (IOException e) {
LOG.error(e);
}
}
private void restoreCopy(VirtualFile file) {
try {
if (file == null) return; // Externally deleted actually.
@@ -917,17 +910,17 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
public void run() {
LOG.debug("Reloading project.");
ProjectImpl projectImpl = (ProjectImpl)project[0];
if (projectImpl.isDisposed()) return;
IProjectStore projectStore = projectImpl.getStateStore();
if (projectImpl.isDisposed()) {
return;
}
final String location = projectImpl.getPresentableUrl();
final List<File> original;
try {
IComponentStore.SaveSession saveSession = projectStore.startSave();
IComponentStore.SaveSession saveSession = projectImpl.getStateStore().startSave();
original = saveSession.getAllStorageFiles(true);
saveSession.finishSave();
}
catch (IOException e) {
catch (Exception e) {
LOG.error(e);
return;
}
@@ -44,7 +44,7 @@ public interface StateStorage {
void finishSave(@NotNull SaveSession saveSession);
void reload(@NotNull Set<String> changedComponents) throws StateStorageException;
void reload(@NotNull Set<String> changedComponents);
interface ExternalizationSession {
void setState(@NotNull Object component, final String componentName, @NotNull Object state, @Nullable final Storage storageSpec) throws StateStorageException;
@@ -53,6 +53,9 @@ public interface StateStorage {
interface SaveSession {
void save() throws StateStorageException;
/**
* Get changed component names
*/
@Nullable
Set<String> analyzeExternalChanges(@NotNull Set<Pair<VirtualFile, StateStorage>> changedFiles);
@@ -188,7 +188,7 @@ public class StorageData {
myHash = -1;
}
public Set<String> getDifference(final StorageData storageData, PathMacroSubstitutor substitutor) {
public Set<String> getChangedComponentNames(@NotNull StorageData storageData, @Nullable PathMacroSubstitutor substitutor) {
Set<String> bothStates = new THashSet<String>(myComponentStates.keySet());
bothStates.retainAll(storageData.myComponentStates.keySet());
@@ -130,7 +130,7 @@ public class MockProjectStore implements IProjectStore {
@Override
@NotNull
public SaveSession startSave() throws IOException {
public SaveSession startSave() {
throw new UnsupportedOperationException("Method startSave not implemented in " + getClass());
}