StreamProvider.isVersioningRequired

This commit is contained in:
Vladimir Krivosheev
2013-09-20 17:08:40 +02:00
parent 54e6582e8c
commit 460ef477e3
10 changed files with 138 additions and 160 deletions
@@ -18,22 +18,16 @@ package com.intellij.openapi.components;
import com.intellij.openapi.application.PathMacroFilter;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.io.FileUtil;
import org.jdom.Attribute;
import org.jdom.Comment;
import org.jdom.Element;
import org.jdom.Text;
import org.jdom.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* @author Eugene Zhuravlev
* @since Dec 6, 2004
*/
public abstract class PathMacroMap {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.PathMacroMap");
private static final Logger LOG = Logger.getInstance(PathMacroMap.class);
public abstract String substitute(String text, boolean caseSensitive);
@@ -41,15 +35,10 @@ public abstract class PathMacroMap {
substitute(e, caseSensitive, false);
}
public final void substitute(@NotNull Element e, boolean caseSensitive, final boolean recursively,
@Nullable PathMacroFilter filter) {
List content = e.getContent();
//noinspection ForLoopReplaceableByForEach
for (int i = 0, contentSize = content.size(); i < contentSize; i++) {
Object child = content.get(i);
public final void substitute(@NotNull Element e, boolean caseSensitive, boolean recursively, @Nullable PathMacroFilter filter) {
for (Content child : e.getContent()) {
if (child instanceof Element) {
Element element = (Element)child;
substitute(element, caseSensitive, recursively, filter);
substitute((Element)child, caseSensitive, recursively, filter);
}
else if (child instanceof Text) {
Text t = (Text)child;
@@ -64,16 +53,11 @@ public abstract class PathMacroMap {
}
}
List attributes = e.getAttributes();
//noinspection ForLoopReplaceableByForEach
for (int i = 0, attributesSize = attributes.size(); i < attributesSize; i++) {
Object attribute1 = attributes.get(i);
Attribute attribute = (Attribute)attribute1;
for (Attribute attribute : e.getAttributes()) {
if (filter == null || !filter.skipPathMacros(attribute)) {
final String value = (recursively || (filter != null && filter.recursePathMacros(attribute)))
? substituteRecursively(attribute.getValue(), caseSensitive)
: substitute(attribute.getValue(), caseSensitive);
attribute.setValue(value);
attribute.setValue((recursively || (filter != null && filter.recursePathMacros(attribute)))
? substituteRecursively(attribute.getValue(), caseSensitive)
: substitute(attribute.getValue(), caseSensitive));
}
}
}
@@ -119,10 +119,8 @@ public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IM
public void load(@NotNull final Element rootElement) throws IOException {
super.load(rootElement);
final List attributes = rootElement.getAttributes();
for (Object attribute : attributes) {
final Attribute attr = (Attribute)attribute;
myOptions.put(attr.getName(), attr.getValue());
for (Attribute attribute : rootElement.getAttributes()) {
myOptions.put(attribute.getName(), attribute.getValue());
}
}
@@ -16,11 +16,5 @@
package com.intellij.openapi.components.impl.stores;
public interface ComponentVersionListener {
ComponentVersionListener EMPTY = new ComponentVersionListener(){
public void componentStateChanged(String componentName) {
}
} ;
void componentStateChanged(String componentName);
}
@@ -134,7 +134,9 @@ public class FileBasedStorage extends XmlElementStorage {
public void resetProviderCache() {
myProviderUpToDateHash = -1;
myProviderVersions = null;
if (myRemoteVersionProvider != null) {
myRemoteVersionProvider.myProviderVersions = null;
}
}
private class FileSaveSession extends MySaveSession {
@@ -322,7 +324,7 @@ public class FileBasedStorage extends XmlElementStorage {
@Nullable
public File updateFileExternallyFromStreamProviders() throws IOException {
StorageData loadedData = loadData(true, myListener);
StorageData loadedData = loadData(true);
Document document = getDocument(loadedData);
if (physicalContentNeedsSave(document)) {
File file = new File(myFile.getAbsolutePath());
@@ -546,6 +546,11 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
private static class OldStreamProviderManager extends StreamProvider implements CurrentUserHolder {
private final List<OldStreamProviderAdapter> myStreamProviders = new SmartList<OldStreamProviderAdapter>();
@Override
public boolean isVersioningRequired() {
return true;
}
@Override
public boolean isEnabled() {
for (StreamProvider provider : myStreamProviders) {
@@ -14,6 +14,15 @@ public abstract class StreamProvider {
public abstract boolean isEnabled();
/**
* If true, special version file per storage file will keep version of component.
* On load remote data will be ignored if local version of component is higher.
* If your storage is always in connected state (for example, git provides you local working copy), you don't need it.
*/
public boolean isVersioningRequired() {
return false;
}
/**
* fileSpec Only main fileSpec, not version
*/
@@ -59,9 +59,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
private final Map<String, Object> myStorageComponentStates = new THashMap<String, Object>(); // at loading we store Element, on setState Integer of hash// at loading we store Element, on setState Integer of hash
private final ComponentVersionProvider myLocalVersionProvider;
private final ComponentVersionProvider myRemoteVersionProvider;
protected TObjectLongHashMap<String> myProviderVersions;
protected final RemoteComponentVersionProvider myRemoteVersionProvider;
protected ComponentVersionListener myListener = new ComponentVersionListener(){
@Override
@@ -72,7 +70,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
private boolean myDisposed;
protected XmlElementStorage(@Nullable final TrackingPathMacroSubstitutor pathMacroSubstitutor,
protected XmlElementStorage(@Nullable TrackingPathMacroSubstitutor pathMacroSubstitutor,
@NotNull Disposable parentDisposable,
@NotNull String rootElementName,
@Nullable StreamProvider streamProvider,
@@ -86,24 +84,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
Disposer.register(parentDisposable, this);
myLocalVersionProvider = localComponentVersionsProvider;
myRemoteVersionProvider = new ComponentVersionProvider() {
@Override
public long getVersion(String name) {
if (myProviderVersions == null) {
loadProviderVersions();
}
return myProviderVersions.get(name);
}
@Override
public void changeVersion(String name, long version) {
if (myProviderVersions == null) {
loadProviderVersions();
}
myProviderVersions.put(name, version);
}
};
myRemoteVersionProvider = streamProvider == null || !streamProvider.isVersioningRequired() ? null : new RemoteComponentVersionProvider();
}
protected boolean isDisposed() {
@@ -145,12 +126,12 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
return myLoadedData;
}
myLoadedData = loadData(true, myListener);
myLoadedData = loadData(true);
return myLoadedData;
}
@NotNull
protected StorageData loadData(boolean useProvidersData, @SuppressWarnings("UnusedParameters") ComponentVersionListener listener) throws StateStorageException {
protected StorageData loadData(boolean useProvidersData) throws StateStorageException {
Document document = loadDocument();
StorageData result = createStorageData();
@@ -158,10 +139,19 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
loadState(result, document.getRootElement());
}
if (myStreamProvider != null && useProvidersData && myStreamProvider.isEnabled()) {
if (useProvidersData && myStreamProvider != null && myStreamProvider.isEnabled()) {
for (RoamingType roamingType : RoamingType.values()) {
if (roamingType != RoamingType.DISABLED && roamingType != RoamingType.GLOBAL) {
loadProviderData(result, roamingType, myStreamProvider);
try {
Document sharedDocument = StorageUtil.loadDocument(myStreamProvider.loadContent(myFileSpec, roamingType));
if (sharedDocument != null) {
filterOutOfDateAndDisabledForRoamingComponents(sharedDocument.getRootElement(), roamingType);
loadState(result, sharedDocument.getRootElement());
}
}
catch (Exception e) {
LOG.warn(e);
}
}
}
}
@@ -169,19 +159,6 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
return result;
}
private void loadProviderData(StorageData result, RoamingType roamingType, StreamProvider streamProvider) {
try {
Document sharedDocument = StorageUtil.loadDocument(streamProvider.loadContent(myFileSpec, roamingType));
if (sharedDocument != null) {
filterOutOfDateAndDisabledForRoamingComponents(sharedDocument.getRootElement(), roamingType);
loadState(result, sharedDocument.getRootElement());
}
}
catch (Exception e) {
LOG.warn(e);
}
}
protected void loadState(final StorageData result, final Element element) throws StateStorageException {
if (myPathMacroSubstitutor != null) {
myPathMacroSubstitutor.expandPaths(element);
@@ -474,10 +451,13 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
if (StorageUtil.doSendContent(streamProvider, myFileSpec, actualDocument, roamingType, true)) {
result = true;
}
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);
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);
}
}
}
catch (IOException e) {
@@ -554,7 +534,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
@Override
public void reload(@NotNull final Set<String> changedComponents) throws StateStorageException {
final StorageData storageData = loadData(false, myListener);
final StorageData storageData = loadData(false);
final StorageData oldLoadedData = myLoadedData;
@@ -582,8 +562,16 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
Iterator<Element> iterator = element.getContent(new ElementFilter(StorageData.COMPONENT)).iterator();
while (iterator.hasNext()) {
String name = iterator.next().getAttributeValue(StorageData.NAME);
long remoteVersion;
if (myComponentRoamingManager.getRoamingType(name) != roamingType || (remoteVersion = myRemoteVersionProvider.getVersion(name)) <= myLocalVersionProvider.getVersion(name)) {
if (myComponentRoamingManager.getRoamingType(name) != roamingType) {
iterator.remove();
}
if (myRemoteVersionProvider == null) {
continue;
}
long remoteVersion = myRemoteVersionProvider.getVersion(name);
if (remoteVersion <= myLocalVersionProvider.getVersion(name)) {
iterator.remove();
}
else {
@@ -592,30 +580,50 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
}
}
private void loadProviderVersions() {
if (myStreamProvider == null) {
return;
@Nullable
Document logComponents() throws StateStorageException {
return mySession instanceof MySaveSession ? getDocument(((MySaveSession)mySession).myStorageData) : null;
}
protected class RemoteComponentVersionProvider implements ComponentVersionProvider {
protected TObjectLongHashMap<String> myProviderVersions;
@Override
public long getVersion(String name) {
if (myProviderVersions == null) {
loadProviderVersions();
}
return myProviderVersions == null ? -1 : myProviderVersions.get(name);
}
myProviderVersions = new TObjectLongHashMap<String>();
for (RoamingType type : RoamingType.values()) {
Document doc = null;
if (myStreamProvider.isEnabled()) {
@Override
public void changeVersion(String name, long version) {
if (myProviderVersions == null) {
loadProviderVersions();
}
if (myProviderVersions != null) {
myProviderVersions.put(name, version);
}
}
private void loadProviderVersions() {
assert myStreamProvider != null;
if (!myStreamProvider.isEnabled()) {
return;
}
myProviderVersions = new TObjectLongHashMap<String>();
for (RoamingType type : RoamingType.values()) {
try {
doc = StorageUtil.loadDocument(myStreamProvider.loadContent(myFileSpec + VERSION_FILE_SUFFIX, type));
Document doc = StorageUtil.loadDocument(myStreamProvider.loadContent(myFileSpec + VERSION_FILE_SUFFIX, type));
if (doc != null) {
StateStorageManagerImpl.loadComponentVersions(myProviderVersions, doc);
}
}
catch (IOException e) {
LOG.debug(e);
}
}
if (doc != null) {
StateStorageManagerImpl.loadComponentVersions(myProviderVersions, doc);
}
}
}
@Nullable
Document logComponents() throws StateStorageException {
return mySession instanceof MySaveSession ? getDocument(((MySaveSession)mySession).myStorageData) : null;
}
}
@@ -572,7 +572,7 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
schemeKey.getExternalInfo().setCurrentFileName(fileName);
}
private static long computeHashValue(final Document document) throws IOException {
private static long computeHashValue(final Document document) {
return JDOMUtil.getTreeHash(document);
}
@@ -54,37 +54,32 @@ public class StorageData {
}
public void load(@NotNull Element rootElement) throws IOException {
final Element[] elements = JDOMUtil.getElements(rootElement);
for (Element element : elements) {
if (element.getName().equals(COMPONENT)) {
final String name = element.getAttributeValue(NAME);
for (Iterator<Element> iterator = rootElement.getChildren(COMPONENT).iterator(); iterator.hasNext(); ) {
Element element = iterator.next();
String name = element.getAttributeValue(NAME);
if (name == null) {
LOG.info("Broken content in file : " + this);
continue;
}
if (name == null) {
LOG.info("Broken content in file : " + this);
continue;
iterator.remove();
if (element.getAttributes().size() > 1 || !element.getChildren().isEmpty()) {
assert element.getAttributeValue(NAME) != null : "No name attribute for component: " + name + " in " + this;
Element existingElement = myComponentStates.get(name);
if (existingElement != null) {
element = mergeElements(name, element, existingElement);
}
element.detach();
if (element.getAttributes().size() > 1 || !element.getChildren().isEmpty()) {
assert element.getAttributeValue(NAME) != null : "No name attribute for component: " + name + " in " + this;
Element existingElement = myComponentStates.get(name);
if (existingElement != null) {
element = mergeElements(name, element, existingElement);
}
myComponentStates.put(name, element);
}
myComponentStates.put(name, element);
}
}
}
private static Element mergeElements(final String name, final Element element1, final Element element2) {
ExtensionPoint<XmlConfigurationMerger> point = Extensions.getRootArea().getExtensionPoint("com.intellij.componentConfigurationMerger");
XmlConfigurationMerger[] mergers = point.getExtensions();
for (XmlConfigurationMerger merger : mergers) {
for (XmlConfigurationMerger merger : point.getExtensions()) {
if (merger.getComponentName().equals(name)) {
return merger.merge(element1, element2);
}
@@ -17,6 +17,7 @@ package com.intellij.openapi.util;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.StringInterner;
import com.intellij.util.io.URLUtil;
@@ -56,12 +57,11 @@ public class JDOMUtil {
@NotNull
public static List<Element> getChildren(@Nullable Element parent) {
if (parent != null) {
@SuppressWarnings({"UnnecessaryLocalVariable", "unchecked"}) final List<Element> children = parent.getChildren();
return children;
if (parent == null) {
return Collections.emptyList();
}
else {
return Collections.emptyList();
return parent.getChildren();
}
}
@@ -82,8 +82,6 @@ public class JDOMUtil {
return LoggerHolder.ourLogger;
}
private static final String ENCODING = "UTF-8";
public static boolean areElementsEqual(Element e1, Element e2) {
if (e1 == null && e2 == null) return true;
if (e1 == null || e2 == null) return false;
@@ -106,16 +104,12 @@ public class JDOMUtil {
private static int addToHash(int i, @NotNull final Element element) {
i = addToHash(i, element.getName());
final List<Attribute> list = element.getAttributes();
//noinspection ForLoopReplaceableByForEach
for (int j = 0; j < list.size(); j++) {
i = addToHash(i, list.get(j));
for (Attribute aList : element.getAttributes()) {
i = addToHash(i, aList);
}
List<Content> content = element.getContent();
//noinspection ForLoopReplaceableByForEach
for (int j = 0; j < content.size(); j++) {
Content child = content.get(j);
for (Content child : content) {
if (child instanceof Element) {
i = addToHash(i, (Element)child);
}
@@ -137,7 +131,6 @@ public class JDOMUtil {
return i * 31 + s.hashCode();
}
@SuppressWarnings({"unchecked"})
@NotNull
public static Object[] getChildNodesWithAttrs(@NotNull Element e) {
ArrayList<Object> result = new ArrayList<Object>();
@@ -146,18 +139,16 @@ public class JDOMUtil {
return ArrayUtil.toObjectArray(result);
}
@SuppressWarnings({"unchecked"})
@NotNull
public static Content[] getContent(@NotNull final Element m) {
final List list = m.getContent();
return (Content[])list.toArray(new Content[list.size()]);
public static Content[] getContent(@NotNull Element m) {
List<Content> list = m.getContent();
return list.toArray(new Content[list.size()]);
}
@SuppressWarnings({"unchecked"})
@NotNull
public static Element[] getElements(@NotNull final Element m) {
final List list = m.getChildren();
return (Element[])list.toArray(new Element[list.size()]);
public static Element[] getElements(@NotNull Element m) {
List<Element> list = m.getChildren();
return list.toArray(new Element[list.size()]);
}
@NotNull
@@ -186,15 +177,12 @@ public class JDOMUtil {
public static void internElement(@NotNull Element element, @NotNull StringInterner interner) {
element.setName(intern(interner, element.getName()));
final List attributes = element.getAttributes();
for (Object o : attributes) {
Attribute attr = (Attribute)o;
for (Attribute attr : element.getAttributes()) {
attr.setName(intern(interner, attr.getName()));
attr.setValue(intern(interner, attr.getValue()));
}
final List content = element.getContent();
for (Object o : content) {
for (Content o : element.getContent()) {
if (o instanceof Element) {
Element e = (Element)o;
internElement(e, interner);
@@ -226,7 +214,6 @@ public class JDOMUtil {
StringBuilder result = new StringBuilder();
while(true) {
//noinspection EmptyCatchBlock
try {
int each = reader.read();
if (each == -1) break;
@@ -237,7 +224,7 @@ public class JDOMUtil {
result.append("0x").append(StringUtil.toUpperCase(Long.toHexString(each)));
}
}
catch (IOException e) {
catch (IOException ignored) {
}
}
@@ -248,11 +235,7 @@ public class JDOMUtil {
private static class EmptyTextFilter implements Filter {
@Override
public boolean matches(Object obj) {
if (obj instanceof Text) {
final Text t = (Text)obj;
return !CharArrayUtil.containsOnlyWhiteSpaces(t.getText());
}
return true;
return !(obj instanceof Text) || !CharArrayUtil.containsOnlyWhiteSpaces(((Text)obj).getText());
}
}
@@ -375,7 +358,7 @@ public class JDOMUtil {
@NotNull
public static Document loadDocument(@NotNull InputStream stream) throws JDOMException, IOException {
InputStreamReader reader = new InputStreamReader(stream, ENCODING);
InputStreamReader reader = new InputStreamReader(stream, CharsetToolkit.UTF8_CHARSET);
try {
return getSaxBuilder().build(reader);
}
@@ -424,7 +407,7 @@ public class JDOMUtil {
}
public static void writeDocument(@NotNull Document document, @NotNull OutputStream stream, String lineSeparator) throws IOException {
writeDocument(document, new OutputStreamWriter(stream, ENCODING), lineSeparator);
writeDocument(document, new OutputStreamWriter(stream, CharsetToolkit.UTF8_CHARSET), lineSeparator);
}
@@ -433,7 +416,7 @@ public class JDOMUtil {
CharArrayWriter writer = new CharArrayWriter();
writeDocument(document, writer, lineSeparator);
return StringFactory.createShared(writer.toCharArray()).getBytes(ENCODING);
return StringFactory.createShared(writer.toCharArray()).getBytes(CharsetToolkit.UTF8_CHARSET);
}
@NotNull
@@ -529,7 +512,7 @@ public class JDOMUtil {
Format format = Format.getCompactFormat().
setIndent(" ").
setTextMode(Format.TextMode.TRIM).
setEncoding(ENCODING).
setEncoding(CharsetToolkit.UTF8).
setOmitEncoding(false).
setOmitDeclaration(false).
setLineSeparator(lineSeparator);