blob: 9edbad2a24131cf3eeb09706574da3e7f6455d4a [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idea.eclipse.config;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.impl.storage.FileSet;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.HashMap;
import org.jdom.Document;
import org.jdom.JDOMException;
import org.jdom.output.EclipseJDOMUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.util.*;
public class CachedXmlDocumentSet implements FileSet {
protected final Map<String, String> nameToDir = new HashMap<String, String>();
protected final Map<String, Document> savedContent = new HashMap<String, Document>();
protected final Map<String, Document> modifiedContent = new HashMap<String, Document>();
protected final Set<String> deletedContent = new HashSet<String>();
private final Project project;
public CachedXmlDocumentSet(Project project) {
this.project = project;
}
public Document read(final String name) throws IOException, JDOMException {
return read(name, true);
}
public Document read(final String name, final boolean refresh) throws IOException, JDOMException {
return (Document)load(name, refresh).clone();
}
public void write(Document document, String name) throws IOException {
update((Document)document.clone(), name);
}
public String getParent(final String name) {
return nameToDir.get(name);
}
public void register(final String name, final String path) {
nameToDir.put(name, path);
}
protected void assertKnownName(final String name) {
assert nameToDir.containsKey(name) : name;
}
public boolean exists(String name) {
assertKnownName(name);
return !deletedContent.contains(name) && getVFile(name, false) != null;
}
@Nullable
protected VirtualFile getVFile(final String name) {
return getVFile(name, true);
}
@Nullable
protected VirtualFile getVFile(final String name, boolean refresh) {
final VirtualFile file = LocalFileSystem.getInstance().findFileByIoFile(new File(getParent(name), name));
if (file != null && refresh) {
file.refresh(false, true);
if (!file.isValid()) return null;
}
return file;
}
@NotNull
private VirtualFile getOrCreateVFile(final String name) throws IOException {
final VirtualFile vFile = getVFile(name);
if (vFile != null) {
return vFile;
}
else {
final VirtualFile vDir = LocalFileSystem.getInstance().findFileByIoFile(new File(getParent(name)));
if (vDir == null) {
throw new IOException(name + ": file not found");
}
final IOException[] ex = new IOException[1];
final VirtualFile file = ApplicationManager.getApplication().runWriteAction(new Computable<VirtualFile>() {
public VirtualFile compute() {
try {
return vDir.createChildData(this, name);
}
catch (IOException e) {
ex[0] = e;
return null;
}
}
});
if (ex[0] != null) throw ex[0];
return file;
}
}
protected Document load(final String name, boolean refresh) throws IOException, JDOMException {
assertKnownName(name);
final Document logical = modifiedContent.get(name);
if (logical != null) {
return logical;
}
Document physical = savedContent.get(name);
if (physical == null) {
final VirtualFile vFile = deletedContent.contains(name) ? null : getVFile(name, refresh);
if (vFile == null) {
throw new IOException(name + ": file does not exist");
}
final InputStream is = vFile.getInputStream();
try {
physical = JDOMUtil.loadDocument(is);
}
finally {
is.close();
}
savedContent.put(name, physical);
}
return physical;
}
public void preload() {
for (String key : nameToDir.keySet()) {
try {
load(key, true);
}
catch (IOException ignore) {
}
catch (JDOMException ignore) {
}
}
}
public void update(Document content, final String name) {
assertKnownName(name);
modifiedContent.put(name, content);
deletedContent.remove(name);
}
public void delete(String name) {
modifiedContent.remove(name);
savedContent.remove(name);
deletedContent.add(name);
//nameToDir.remove(name);
}
public void listFiles(final List<VirtualFile> list) {
Set<String> existingFiles = new HashSet<String>(savedContent.keySet());
existingFiles.addAll(modifiedContent.keySet());
for (String key : existingFiles) {
try {
if(getVFile(key)==null) {
savedContent.remove(key); // deleted on disk
}
list.add(getOrCreateVFile(key));
}
catch (IOException ignore) {
}
}
Set<String> newFiles = new HashSet<String>(nameToDir.keySet());
newFiles.removeAll(existingFiles);
for (String name : newFiles) {
VirtualFile vFile = getVFile(name);
if (vFile != null) {
list.add(vFile);
}
}
}
@Override
public void listModifiedFiles(List<VirtualFile> list) {
for (String key : modifiedContent.keySet()) {
try {
if (hasChanged(key)) {
list.add(getOrCreateVFile(key));
}
}
catch (IOException ignore) {
}
}
}
public boolean hasChanged() {
for (String key : modifiedContent.keySet()) {
if (hasChanged(key)) {
return true;
}
}
return !deletedContent.isEmpty();
}
private boolean hasChanged(final String key) {
final Document content = modifiedContent.get(key);
final Document physical1 = content == null ? null : content;
final Document physical2 = savedContent.get(key);
if (physical1 != null && physical2 != null) {
return !JDOMUtil.areDocumentsEqual(physical1, physical2);
}
return physical1 != physical2;
}
public void commit() throws IOException {
for (String key : modifiedContent.keySet()) {
if (hasChanged(key)) {
final Document content = modifiedContent.get(key);
if (content != null) {
final Writer writer = new OutputStreamWriter(getOrCreateVFile(key).getOutputStream(this), "UTF-8");
try {
EclipseJDOMUtil.output(content, writer, project);
}
finally {
writer.close();
}
savedContent.put(key, content);
}
}
}
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
for (String deleted : deletedContent) {
VirtualFile file = getVFile(deleted);
if (file != null) {
try {
file.delete(this);
}
catch (IOException ignore) {
}
}
}
deletedContent.clear();
}
});
}
}