Optimized reading external annotations: now they when annotations file is accessed, it's parsed data is stored in cache.

This commit is contained in:
Evgeny Gerashchenko
2012-07-31 20:15:52 +04:00
parent dcd5cad427
commit 7370107616
@@ -17,7 +17,6 @@
package org.jetbrains.jet.lang.resolve.java.extAnnotations;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.io.StreamUtil;
import com.intellij.openapi.util.text.StringUtil;
@@ -28,16 +27,15 @@ import com.intellij.util.IncorrectOperationException;
import com.intellij.util.StringBuilderSpinAllocator;
import com.intellij.util.containers.ConcurrentWeakHashMap;
import com.intellij.util.containers.ConcurrentWeakValueHashMap;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.ConcurrentMap;
@@ -49,6 +47,8 @@ import java.util.concurrent.ConcurrentMap;
*/
@Deprecated
public class CoreAnnotationsProvider extends ExternalAnnotationsProvider {
static int loadDocumentCount = 0;
static {
// This is an ugly workaround for JDOM 1.1 used from application started from Ant 1.8 without forking
System.setProperty("javax.xml.parsers.SAXParserFactory", "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl");
@@ -135,66 +135,81 @@ public class CoreAnnotationsProvider extends ExternalAnnotationsProvider {
externalAnnotationsRoots.add(externalAnnotationsRoot);
}
private Map<String, PsiAnnotation> doCollect(@NotNull PsiModifierListOwner listOwner) {
final List<PsiFile> files = findExternalAnnotationsFiles(listOwner);
if (files == null) {
return Collections.emptyMap();
private Map<PsiFile, MultiMap<String, AnnotationData>> annotationsFileToData = new HashMap<PsiFile, MultiMap<String, AnnotationData>>();
private Map<PsiFile, Long> annotationsFileToModificationStamp = new HashMap<PsiFile, Long>();
@NotNull
private MultiMap<String, AnnotationData> getDataFromFile(@NotNull PsiFile file) {
if (annotationsFileToData.containsKey(file) && file.getModificationStamp() == annotationsFileToModificationStamp.get(file)) {
return annotationsFileToData.get(file);
}
final Map<String, PsiAnnotation> result = new HashMap<String, PsiAnnotation>();
for (PsiFile file : files) {
if (!file.isValid()) continue;
final Document document;
else {
MultiMap<String, AnnotationData> data = new MultiMap<String, AnnotationData>();
annotationsFileToData.put(file, data);
annotationsFileToModificationStamp.put(file, file.getModificationStamp());
Document document;
try {
// CoreLocalVirtualFile.getInputStream() fails with AssertionError
VirtualFile virtualFile = file.getVirtualFile();
InputStream stream = "CoreLocalVirtualFile".equals(virtualFile.getClass().getSimpleName())
? new BufferedInputStream(new FileInputStream(virtualFile.getPath()))
: virtualFile.getInputStream();
document = JDOMUtil.loadDocument(escapeAttributes(StreamUtil.readText(stream)));
//noinspection ConstantConditions
System.out.println("loadDocument count = " + (loadDocumentCount++));
document = JDOMUtil.loadDocument(escapeAttributes(StreamUtil.readText(file.getVirtualFile().getInputStream())));
}
catch (IOException e) {
LOG.error(e);
continue;
return data;
}
catch (JDOMException e) {
LOG.error(e);
continue;
return data;
}
if (document == null) continue;
final Element rootElement = document.getRootElement();
if (rootElement == null) continue;
final String externalName = getExternalName(listOwner, false);
final String oldExternalName = getNormalizedExternalName(listOwner);
Element rootElement = document.getRootElement();
if (rootElement == null) return data;
//noinspection unchecked
for (final Element element : (List<Element>) rootElement.getChildren()) {
final String className = element.getAttributeValue("name");
if (!Comparing.strEqual(className, externalName) && !Comparing.strEqual(className, oldExternalName)) {
continue;
}
for (Element element : (List<Element>) rootElement.getChildren()) {
String ownerName = element.getAttributeValue("name");
if (ownerName == null) continue;
//noinspection unchecked
for (Element annotationElement : (List<Element>) element.getChildren()) {
final String annotationFQN = annotationElement.getAttributeValue("name");
final StringBuilder buf = new StringBuilder();
String annotationFQN = annotationElement.getAttributeValue("name");
StringBuilder buf = new StringBuilder();
//noinspection unchecked
for (Element annotationParameter : (List<Element>) annotationElement.getChildren()) {
buf.append(",");
final String nameValue = annotationParameter.getAttributeValue("name");
String nameValue = annotationParameter.getAttributeValue("name");
if (nameValue != null) {
buf.append(nameValue).append("=");
}
buf.append(annotationParameter.getAttributeValue("val"));
}
final String annotationText =
"@" + annotationFQN + (buf.length() > 0 ? "(" + StringUtil.trimStart(buf.toString(), ",") + ")" : "");
try {
result.put(annotationFQN,
JavaPsiFacade.getInstance(listOwner.getProject()).getElementFactory().createAnnotationFromText(
annotationText, null));
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
String annotationText = "@" + annotationFQN + (buf.length() > 0 ? "(" + StringUtil.trimStart(buf.toString(), ",") + ")" : "");
data.putValue(ownerName, new AnnotationData(annotationFQN, annotationText));
}
}
return data;
}
}
private Map<String, PsiAnnotation> doCollect(@NotNull PsiModifierListOwner listOwner) {
final List<PsiFile> files = findExternalAnnotationsFiles(listOwner);
if (files == null) {
return Collections.emptyMap();
}
Map<String, PsiAnnotation> result = new HashMap<String, PsiAnnotation>();
String externalName = getExternalName(listOwner, false);
String oldExternalName = getNormalizedExternalName(listOwner);
for (PsiFile file : files) {
if (!file.isValid()) continue;
MultiMap<String, AnnotationData> fileData = getDataFromFile(file);
for (AnnotationData annotationData : ContainerUtil.concat(fileData.get(externalName), fileData.get(oldExternalName))) {
try {
result.put(annotationData.annotationClassFqName,
JavaPsiFacade.getInstance(listOwner.getProject()).getElementFactory().createAnnotationFromText(
annotationData.annotationText, null));
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
}
@@ -291,4 +306,14 @@ public class CoreAnnotationsProvider extends ExternalAnnotationsProvider {
}
return sb.toString();
}
private static class AnnotationData {
public String annotationClassFqName;
public String annotationText;
private AnnotationData(String annotationClassFqName, String annotationText) {
this.annotationClassFqName = annotationClassFqName;
this.annotationText = annotationText;
}
}
}