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